Java'da imzasız bayt yapabilir miyiz


185

İmzasız imzalanmış bir baytı dönüştürmeye çalışıyorum. Sorun, aldığım verilerin imzasız olması ve Java imzasız baytı desteklememesi, bu nedenle verileri okuduğunda imzalı gibi davranmasıdır.

Stack Overflow'dan aldığım aşağıdaki çözümle dönüştürmeyi denedim.

public static int unsignedToBytes(byte a)
{
    int b = a & 0xFF;
    return b;
}

Ama yine bayta dönüştürüldüğünde, aynı imzalı verileri alıyorum. Bu veriyi başka bir veri türü kullanamadığım için yalnızca bayt parametresini kabul eden Java işlevine bir parametre olarak bu verileri kullanmaya çalışıyorum. Bu sorunu nasıl düzeltebilirim?


2
Guava: UnsignedBytes.toint (byte değeri)
jacktrades

21
java.lang.Byte.toUnsignedInt (bayt değeri);
themarketka

Yanıtlar:


107

Sorunu anladığımdan emin değilim.

Ben sadece denedim ve bayt -12 (işaretli değer) için tamsayı 244 (imzasız bayt değerine eşdeğer ama bir olarak yazılır) döndürdü int:

  public static int unsignedToBytes(byte b) {
    return b & 0xFF;
  }

  public static void main(String[] args) {
    System.out.println(unsignedToBytes((byte) -12));
  }

Yapmak istediğin şey bu mu?

Java, 244 bytedeğerini C'nin yaptığı gibi bir değer olarak ifade etmesine izin vermez. Byte.MAX_VALUE(127) üzerindeki pozitif tam sayıları ifade etmek için short, intveya gibi başka bir tamsayı türü kullanmanız gerekir long.


1
byte b = (byte)unsignedToBytes((byte) -12); şimdi baskı b deneyin
Jigar Joshi

101
Bunu neden doğru cevap olarak kabul ettiniz? Tek yaptığı, sorunuzda bahsettiğiniz yöntemle tamamen aynı - bir baytı işaretsiz bir tam sayıya dönüştürün.
Adamski

1
Bazen imzalı, bazen imzasız değerlere sahip olmak önemlidir, bu yüzden muhtemelen bu cevabı kabul etmesinin nedeni budur. (bayt) (b & 0xff) herhangi bir anlam ifade etmez, ancak (bayt) (Math.min ((b & 0xff) * 2, 255)) mantıklıdır, örn. bilgisayar grafiklerinde bayt iki kat daha parlaktır. :-)
iirekm

3
Buna byteToUnsigned de denebilir
Hernán Eche

195

Temel öğelerin Java'da imzalanmış olması, bellekte / geçişte nasıl temsil edildikleri ile ilgisizdir - bir bayt sadece 8 bittir ve bunu işaretli bir aralık olarak yorumlayıp yorumlamadığınız size bağlıdır. "Bu imzalandı" veya "bu imzalanmadı" diyecek sihirli bir bayrak yok.

Temel öğeler imzalandıkça Java derleyicisi bir bayta +127'den (veya -128'den düşük) bir değer atamanızı önler. Ancak, bunu başarmak için bir int (veya kısa) küçümsemeyi engelleyecek hiçbir şey yoktur:

int i = 200; // 0000 0000 0000 0000 0000 0000 1100 1000 (200)
byte b = (byte) 200; // 1100 1000 (-56 by Java specification, 200 by convention)

/*
 * Will print a negative int -56 because upcasting byte to int does
 * so called "sign extension" which yields those bits:
 * 1111 1111 1111 1111 1111 1111 1100 1000 (-56)
 *
 * But you could still choose to interpret this as +200.
 */
System.out.println(b); // "-56"

/*
 * Will print a positive int 200 because bitwise AND with 0xFF will
 * zero all the 24 most significant bits that:
 * a) were added during upcasting to int which took place silently
 *    just before evaluating the bitwise AND operator.
 *    So the `b & 0xFF` is equivalent with `((int) b) & 0xFF`.
 * b) were set to 1s because of "sign extension" during the upcasting
 *
 * 1111 1111 1111 1111 1111 1111 1100 1000 (the int)
 * &
 * 0000 0000 0000 0000 0000 0000 1111 1111 (the 0xFF)
 * =======================================
 * 0000 0000 0000 0000 0000 0000 1100 1000 (200)
 */
System.out.println(b & 0xFF); // "200"

/*
 * You would typically do this *within* the method that expected an 
 * unsigned byte and the advantage is you apply `0xFF` only once
 * and than you use the `unsignedByte` variable in all your bitwise
 * operations.
 *
 * You could use any integer type longer than `byte` for the `unsignedByte` variable,
 * i.e. `short`, `int`, `long` and even `char`, but during bitwise operations
 * it would get casted to `int` anyway.
 */
void printUnsignedByte(byte b) {
    int unsignedByte = b & 0xFF;
    System.out.println(unsignedByte); // "200"
}

5
Birçok işlem için fark etmez, ancak bazı işlemler için fark etmez. Her iki şekilde de bir baytı imzasız olarak veya imzasız karakterini kullanabilirsiniz.
Peter Lawrey

62
Potansiyel olarak negatif bir sayıya sahip bir diziye erişmek önemsizdir.
Stefan

3
@Stefan - Telde nasıl temsil edildikleri bağlamında alakasız demek istedim.
Adamski

6
Hangi soru ile biraz alakasız. Onu sadece bayt parametrelerini kabul eden bir işleve geçirmesi gerektiğini belirttiğinden, hava durumu önemli değildir, onu bir tek boynuzlu atın bayt temsili olarak yorumlarız. Java bunu her zaman işaretli bir sayı olarak görür; bu, bu işlev parametreyi dizin olarak kullandığında bir örnek için sorun yaratabilir. Ancak adil olmak gerekirse, ben de soruyu cevaplamadığı için diğer ilk 2 cevabı da düşürdüm.
Stefan

2
@Stefan +1 sizin için. 256 elemanlık bir diziye erişmek için bayt kullanıyorsanız kesinlikle alakalı. Herkesin Java veya C # geçmeden önce C ve C ++ öğrenmeye başlamalıdır yüzden göstermek için mükemmel bir örnek
Gianluca Ghettini

46

Java'da imzasız baytlarla çalışmak için eksiksiz kılavuz:

Java'da imzasız bayt

(Bu cevap için kaynak.)


Java Dili, unsignedanahtar kelime gibi bir şey sağlamaz . Özelliğe bytegöre A değeri −128 - 127 arasında bir değeri temsil eder. Örneğin, bytebir intJava'ya yayınlanırsa ilk bit işaret ve kullanım işareti uzantısı olarak yorumlanır .

Bununla birlikte, hiçbir şey bytebasitçe 8 bit olarak görmenizi engellemez ve bu bitleri 0 ile 255 arasında bir değer olarak yorumlamaz. Sadece yorumunuzu başka birinin yöntemine zorlamak için yapabileceğiniz hiçbir şey olmadığını unutmayın. Bir yöntem a'yı kabul ediyorsa byte, aksi belirtilmedikçe bu yöntem −128 ile 127 arasında bir değer kabul eder.

Size kolaylık sağlamak için birkaç yararlı dönüşüm / manipülasyon aşağıda verilmiştir:

İnt için / int'den dönüşümler

// From int to unsigned byte
int i = 200;                    // some value between 0 and 255
byte b = (byte) i;              // 8 bits representing that value

// From unsigned byte to int
byte b = 123;                   // 8 bits representing a value between 0 and 255
int i = b & 0xFF;               // an int representing the same value

(Veya Java 8+ kullanıyorsanız, kullanın Byte.toUnsignedInt.)

Ayrıştırma / biçimlendirme

En iyi yol yukarıdaki dönüşümleri kullanmaktır:

// Parse an unsigned byte
byte b = (byte) Integer.parseInt("200");

// Print an unsigned byte
System.out.println("Value of my unsigned byte: " + (b & 0xFF));

Aritmetik

2-tamamlayıcı gösterimi toplama, çıkarma ve çarpma için "sadece çalışır":

// two unsigned bytes
byte b1 = (byte) 200;
byte b2 = (byte) 15;

byte sum  = (byte) (b1 + b2);  // 215
byte diff = (byte) (b1 - b2);  // 185
byte prod = (byte) (b2 * b2);  // 225

Bölüm, işlenenlerin manuel olarak dönüştürülmesini gerektirir:

byte ratio = (byte) ((b1 & 0xFF) / (b2 & 0xFF));

1
'char' bir sayıyı temsil etmez.
oturum kapat

26
Kısaca söylemek gerekirse: Yanılıyorsunuz .
aioobe

36

Java'da ilkel imzalanmamış bayt yoktur. Her zamanki şey onu daha büyük bir türe dökmektir:

int anUnsignedByte = (int) aSignedByte & 0xff;

Bir int için oyuncular gerekli mi?
nich

Örtük bir kadro olabilir, ancak her iki şekilde de kadro vardır. Ve bu kadro imzalı uzantı yapıyor. Ve bu bir problem. Açık bir oyuncu seçimi yaparsanız, en azından bunun olduğunu görebilirsiniz.
Foo


4

Yan not, yazdırmak istiyorsanız, şunu söyleyebilirsiniz:

byte b = 255;
System.out.println((b < 0 ? 256 + b : b));

6
neden bu kadar karmaşık? println(b & 0xff)yeterli
phuclv

0

Eğer böyle bir şey arıyorsanız düşünüyorum.

public static char toUnsigned(byte b) {
    return (char) (b >= 0 ? b : 256 + b);
}

0

Adamski en iyi cevabı verdi, ancak tam değil, bu yüzden cevabını okuyun, çünkü ben olmadığım ayrıntıları açıklıyor.

İmzasız bir bayt geçirilmesini gerektiren bir sistem işleviniz varsa, otomatik olarak imzasız bir bayt olarak işlem göreceğinden, imzalı bir bayt iletebilirsiniz.

Dolayısıyla, bir sistem işlevi dört bayt gerektiriyorsa, örneğin, 192 168 0 1 imzasız bayt olarak -64 -88 0 1'i geçebilirsiniz ve işlev yine de çalışır, çünkü bunları işleve geçirme eylemi bunların işaretini kaldıracaktır. .

Ancak, java.io okuma yöntemlerinden bazıları int olarak görüntülenmemiş baytları döndürürken, sistem işlevleri platformlar arası uyumluluk için sınıfların arkasına gizlendiğinden bu sorunu yaşamanız olası değildir.

Bu çalışmayı görmek istiyorsanız, bir dosyaya imzalı bayt yazmayı deneyin ve imzalanmamış bayt olarak tekrar okuyun.


1
İmzalı veya imzasız bayt diye bir şey yoktur.
Vlastimil Ovčáčík

Örneğinizdeki baytları tam olarak nasıl yazıyordunuz ve okuyordunuz?
Vlastimil Ovčáčík

0

Ayrıca şunları da yapabilirsiniz:

public static int unsignedToBytes(byte a)
{
    return (int) ( ( a << 24) >>> 24);
}    

Açıklama:

diyelimki a = (byte) 133;

Bellekte şu şekilde saklanır: "1000 0101" (onaltılık 0x85)

Böylece temsili imzasız = 133, imzalı = -123 (2'nin tamamlayıcısı olarak)

a << 24

Sola kaydırma, sola 24 bit gerçekleştirildiğinde, sonuç şimdi şu şekilde temsil edilen 4 baytlık bir tam sayıdır:

"10000101 00000000 00000000 00000000" (veya onaltılı olarak "0x85000000")

o zaman sahibiz

(a << 24) >>> 24

ve yine sağ 24 bitte kayar ancak baştaki sıfırlarla dolar. Sonuç:

"00000000 00000000 00000000 10000101" (veya onaltılı olarak "0x00000085")

ve bu 133'e işaret eden imzasız temsil.

Eğer yayınlamaya çalışırsanız a = (int) a; , 2'nin tamamlayıcı temsilini tutar ve 2'nin tamamlayıcısı olarak da saklar:

(int) "10000101" -> "11111111 11111111 11111111 10000101"

Ve bu şu şekilde tercüme edilir: -123


2
2019'da bu gereksiz. Sadece kullan java.lang.Byte.toUnsignedInt(byte value). Ve henüz Java 8 kullanmıyorsanız, en kısa sürede yükseltin. Java 7 ve önceki sürümleri kullanım ömrünün sonuna gelmiştir.
Stephen C

0

Parametre olarak sadece bir bayt kabul Java işlevine bir parametre olarak bu verileri kullanmaya çalışıyorum

Bu, 2 ^ 32-1'den daha büyük bir değer vermek istediğiniz bir tamsayıyı kabul eden bir işlevden önemli ölçüde farklı değildir.

Bu, fonksiyonun nasıl tanımlandığına ve belgelendiğine bağlıdır; Üç olasılık görebiliyorum:

  1. Fonksiyonun bayta imzasız bir değer olarak davrandığını açıkça belgeleyebilir, bu durumda fonksiyon muhtemelen beklediğiniz şeyi yapmalıdır, ancak yanlış uygulanmış gibi görünecektir. Tamsayı durumunda, işlev büyük olasılıkla parametreyi imzasız bir tamsayı olarak bildirir, ancak bu bayt durumu için mümkün değildir.

  2. Bu bağımsız değişkenin değerinin sıfırdan (veya belki de ona eşit) büyük olması gerektiğini belgeleyebilir; bu durumda, işlevi yanlış kullandığınızdan (aralık dışı bir parametre geçirerek) ve tasarlandığından daha fazlasını yapmasını bekleyebilirsiniz. yapmak. Bir miktar hata ayıklama desteği ile, işlevin bir istisna atmasını veya bir iddiayı başarısız olmasını bekleyebilirsiniz.

  3. Dokümantasyon hiçbir şey söyleyemez, bu durumda negatif bir parametre negatif bir parametredir ve bunun herhangi bir anlamı olup olmadığı işlevin ne yaptığına bağlıdır. Bu anlamsızsa, işlev gerçekten (2) olarak tanımlanmalı / belgelenmelidir. Bu, açık olmayan bir şekilde anlamlıysa (örneğin, bir diziye dizine eklemek için negatif olmayan değerler kullanılır ve dizinin sonundan -1 dizinine kadar son dizine geri dönmek için negatif değerler kullanılır), belgeler bunun ne olduğunu söylemelidir. ve yine de yapmasını istediğiniz şey olmadığını umuyorum.


Hmmm, sanırım baytların imzasıyla ilgili başka bir soruya yönelik bir cevap yayınladım, ancak sanırım burada hala biraz alakalı ...
Kevin Martin

-1

İmzalı bir bayttan geçirilmesi gereken bir işleviniz varsa, işaretsiz bir bayt iletirseniz ne yapmasını beklersiniz?

Neden başka bir veri türü kullanmıyorsunuz?

Bir baytı, basit veya hiç çevirisiz imzasız bir bayt olarak kullanabilirsiniz. Her şey nasıl kullanıldığına bağlıdır. Bununla ne yapmak istediğinizi açıklığa kavuşturmanız gerekir.


-1

Java'nın dilde imzasız bayt içermemesi sinir bozucu (C'den geliyor) gibi görünse de, basit bir "b & 0xFF" işlemi (nadir) gerçekten ihtiyaç duyulan durumlar. Bitler aslında değişmez - sadece yorum (bu sadece değerler üzerinde bazı matematik işlemleri yaparken önemlidir).


Başkalarının cevabına bak, cevabının en iyi / yararlı olduğunu mu düşünüyorsun? biraz tarif ve yorum eklemek
Jubin Patel

8
Sadece rastlamadığın için nadir değil. Bir protokol uygulamayı deneyin ve bunu bir milyon kez karşılaşacaksınız. Can sıkıcı şey, baytlarla uğraştığım kullanım vakalarının büyük çoğunluğunun işaretsiz baytlarla uğraşmak istediğinizdir (çünkü bunlar sayı değil bayttır). Çılgın şey, HERHANGİ bir şekilde bit işleminin bir int'e dönüştürmesi, yani herhangi bir "negatif" değerin genişletildiğinde tamamen farklı değerler olacağı anlamına gelir. Evet, her zaman maskeleyerek etrafta dolaşabilirsiniz, ancak zaman kaybı, işlemci ve unutursanız gerçekten belirsiz hatalara neden olur.
Thor84no

Thor84no ile aynı fikirdeyim: baytlar sayı değildir ve işareti olmamalıdır. Diğer taraftan, sayı olmadıkları için + ve - operatörlerine bile sahip olmamalı / kullanmamalıyız. Sadece bitsel operatörleri kullanmak iyi çalışır, diğer yandan vardiya operatörleri istediği gibi çalışmaz ve gerçekten de java bir baytın int'e kaydırılmasını sağlar.
user1708042

1
@ VlastimilOvčáčík Bu durumda tam anlamıyla imkansız olan bu, rahatsız edici şey. İhtiyacınız olan x & 0xFFher yerde tekrar edersiniz veya behaveLikeAnUnsignedByte(x)her yerde olduğu gibi tekrarlarsınız . Bu, bir bayt değeri veya imzasız olması gereken bir bayt dizisi kullandığınız her bir yer için gereklidir, bu tekrardan kaçınmanın makul bir yolu yoktur. Sen olamaz okur ve bir bayt değişkene sadece tek referansla bayt değerleri yazan bir protokolün uygulanmasını yazın. Basit görüşünüz neden düzeltmek için hiç umursamadıklarını açıklayabilir.
Thor84no

-1

Java'da imzasız bir bayt yoktur, ancak bir bayt görüntülemek istiyorsanız,

int myInt = 144;

byte myByte = (byte) myInt;

char myChar = (char) (myByte & 0xFF);

System.out.println("myChar :" + Integer.toHexString(myChar));

Çıktı:

myChar : 90

Daha fazla bilgi için lütfen Java'da onaltılık / bayt değeri nasıl görüntüleneceğini kontrol edin .


Bunu kendiniz tanımlamanıza gerek yok. java.lang.Byte.toUnsignedInt(byte value);bunun için var.
Alexander - Monica'yı eski

-2

Java sınırlamalarına göre, geçerli veri tipi biçiminde imzasız bayt neredeyse imkansızdır. Uyguladığınız şey için başka bir dilin başka kütüphanelerini de arayabilir ve daha sonra JNI kullanarak arayabilirsiniz .


İmzalı bir bayt olarak saklamak istediğini sanmıyorum. İmzalı bir bayt olarak alıyor ve mükemmel bir şekilde geçerli bir int olarak saklamak istiyor. Onun sorunu girdi aldığı her yerde 0 ile 255 arasında bir bayt olarak bir değeri temsil etmesidir, ancak Java bunu iki imzalı işaretli değeri tamamlar çünkü java imzalı baytları desteklemez.
Zac

-2

Evet ve hayır. Bu sorunla uğraşıyorum. Bunu anladığım gibi:

Gerçek şu ki, java -128 ile 127 arasında bir interger imzaladı.

public static int toUnsignedInt(byte x) {
    return ((int) x) & 0xff;
}

Örneğin imzasız olarak -12 imzalı numara eklerseniz, 244 elde edersiniz. Ancak bu numarayı imzalı olarak tekrar kullanabilirsiniz, imzalı hale geri döndürülmeli ve tekrar -12 olacaktır.

Java baytına 244 eklemeyi denerseniz, outOfIndexException özelliğine sahip olursunuz.

Şerefe ..


3
Bunu kendiniz tanımlamanıza gerek yok. java.lang.Byte.toUnsignedInt(byte value);bunun için var.
Alexander - Monica'yı eski

-3

Java'da imzasız baytlar istiyorsanız, yalnızca ilgilendiğiniz sayıdan 256 çıkarın. İkisinin tamamlayıcısını negatif bir değerle üretir , bu da imzasız baytlarda istenen sayıdır.

Misal:

int speed = 255; //Integer with the desired byte value
byte speed_unsigned = (byte)(speed-256);
//This will be represented in two's complement so its binary value will be 1111 1111
//which is the unsigned byte we desire.

NXT tuğlasını programlamak için leJOS kullanırken bu tür kirli kesmek kullanmanız gerekir .


255'in ikili değerinin de 1111 1111 olduğunu fark edersiniz, bu yüzden çıkarma gerekmez, değil mi?
Nick White

@NickWhite, evet ikili. Ancak java uses'in 2'nin tamamlayıcısı, 255 değil 11111111
XapaJIaMnu

Üzgünüm, ama bu sadece yanlış. Bazı deneyleri deneyin. İçindeki değer speed_unsignedimzalandı. Yazdırın ve görün. (Ve - 256burada hiçbir şey başaramaz.)
Stephen C
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.