unsigned byte

Etwas das sich mir bis heute nicht erschließt. Da baut man LAmbdas, Streams, Module und allen möglichen Kram ein aber ein einfaches ubyte o.ä. das man wirklich oft braucht das gibts nicht....
naja - Spätestens wenn es auch um die Arithmetik mit vorzeichenlosen Typen geht, kann es durchaus komplex werden. Etwas findet man also eine Antwort in http://www.mi.fu-berlin.de/inf/grou...avaUndvorzeichenloseDatentypen.pdf?1346661562

Und wenn man in die .Net Welt geht, dann kommt man bei vorzeichenlosen typen wie uint auch sofort in einen Bereich, der nicht CLS Compliant ist. Und wenn man in dem .Net Bereich etwas sucht, dann findet man auch diverse Ausführungen z.B. https://stackoverflow.com/questions/6301/why-is-array-length-an-int-and-not-an-uint

Das einfach nur als kleine Denkanregung ohne irgend eine Position vertreten zu wollen.
 
Was dazu kommt: es würde einen Haufen mehr an Bytecode Instructions bedeuten, für einen ziemlich kleinen Gewinn. Eher wäre ein unsigned int/unsigned long sinnvoll, die nutzt man im Gegensatz zu unsigned bytes wirklich oft.

Ich hatte eigentlich noch nie den Bedarf nach explizit unsigned byte. Wenn man damit rechnen will, kann man eigentlich auch immer direkt int zum Rechnen nutzen (wird ja bei byte und short sowieso gemacht). Und wenn man nicht damit rechnet ist's eh egal.
 
Was dazu kommt: es würde einen Haufen mehr an Bytecode Instructions bedeuten, für einen ziemlich kleinen Gewinn. Eher wäre ein unsigned int/unsigned long sinnvoll, die nutzt man im Gegensatz zu unsigned bytes wirklich oft.

Ich hatte eigentlich noch nie den Bedarf nach explizit unsigned byte. Wenn man damit rechnen will, kann man eigentlich auch immer direkt int zum Rechnen nutzen (wird ja bei byte und short sowieso gemacht). Und wenn man nicht damit rechnet ist's eh egal.

Dann kannst du mal einen DICOM parser schreiben wie ich es musste. Die Files beinhalten alle verschiedenen Typen von Variablen in vorher im File festgelegter order. Also entweder Little- or Big-Endian. Was ein Spaß das in Java Variablen zu Parsen.
 
Dann kannst du mal einen DICOM parser schreiben wie ich es musste. Die Files beinhalten alle verschiedenen Typen von Variablen in vorher im File festgelegter order. Also entweder Little- or Big-Endian. Was ein Spaß das in Java Variablen zu Parsen.
Und wo musst du da mit einzelnen bytes rechnen?

Dass das kein Spaß ist glaub ich sofort, nur den Zusammenhang mit signed/unsigned byte seh ich da grad nicht...
Man darf halt an ein paar Stellen nicht einfach stumpf casten
 
Und wo musst du da mit einzelnen bytes rechnen?

Dass das kein Spaß ist glaub ich sofort, nur den Zusammenhang mit signed/unsigned byte seh ich da grad nicht...

Wenn du jeden char einzeln liest und davon 4 zu einem long zusammen bauen must dann must du halt die drei bytes welche nicht das high byte darstellen (je nach Endian das erste oder letzte) als Byte behandeln
 
Ich sehe das wie Thallius. Es gibt kaum etwas schrecklicheres in Java als diesen byte-Datentyp. Wer auf Byte-Ebene arbeitet, will in der Regel gerade kein Vorzeichen oder damit rechnen, sondern schlicht Bitoperationen durchführen und zwar ohne, dass das Vorzeichen oder der automatische cast zu int dazwischenfunken. Mit byte zu arbeiten, ist in Java immer ätzend, z. B. & 0xff -> int -> cast erforderlich.
 
Wenn du jeden char einzeln liest und davon 4 zu einem long zusammen bauen must dann must du halt die drei bytes welche nicht das high byte darstellen (je nach Endian das erste oder letzte) als Byte behandeln
Um Bytes als Bytes zu behandeln gibt es in Java, naja, byte.

4 Bytes in entsprechender Endian'ness zu interpretieren braucht immerhin eine ganze Zeile Code:

[CODE lang="java" highlight="3,4"]byte[] bytes = {(byte)0b10101010, (byte)0b11110000, (byte)0b00001111, (byte)0b01010101};

final int be = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getInt();
final int le = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt();

System.out.printf("BE: %32s%n", Integer.toBinaryString(be));
System.out.printf("LE: %32s%n", Integer.toBinaryString(le));[/CODE]

Wie gesagt: ich seh das Problem einfach nicht, vielleicht denk ich aber auch in die völlig falsche Richtung.

Hast du mal ein Beispiel, wo man damit wirklich ein Problem hat, welches man nicht einfach lösen kann?
 
Zuletzt bearbeitet:
Ich sehe das wie Thallius. Es gibt kaum etwas schrecklicheres in Java als diesen byte-Datentyp. Wer auf Byte-Ebene arbeitet, will in der Regel gerade kein Vorzeichen oder damit rechnen, sondern schlicht Bitoperationen durchführen und zwar ohne, dass das Vorzeichen oder der automatische cast zu int dazwischenfunken. Mit byte zu arbeiten, ist in Java immer ätzend, z. B. & 0xff -> int -> cast erforderlich.
Störend ist dabei doch im wesentlichen nur der Cast nach int, das Vorzeichen ist auf Bit-Ebene ja egal (bis auf den Rechts-Shift)?

Die Rechenoperationen direkt für Byte anzubieten hätte halt einen Haufen mehr ans Bytecode-Instruktions bedeutet, und wenn man das gleiche dann noch für short gemacht hätte, wären alle möglichen Instruktionen ziemlich schnell aufgebraucht gewesen und die Änderungen der letzten Jahre wären nicht möglich gewesen.

Gibt es irgendwelche bit-Operationen, die nicht auch genauso gut auf int wie auf byte durchführbar sind?
 
Ich habe mal in Java die Ausgabe einer Hardwarekommunikation auswerten müssen. (Ok, Java hab ich selber gewählt, aber eine wirkliche Wahl war das auch nicht.)

Ja, es ist schon abenteuerlich den Kram, den ein FPGA aus einer SPI-Schnittstelle rausrotzt, in Java weiterverarbeiten zu wollen. Wenn halt nur ein Byte vorgesehen ist um einen Messageframe als Userdata oder Housekeepingdata zu kennzeichnen - naja, was willste machen. Danach ein Short aus zwei Bytes um die Länge anzugeben, usw.

Aber es ging...ein Hoch auf die ByteBufferklasse, die macht es wieder relativ einfach. Das Nervigste war auch bei mir das ständige ungefragte Autogecaste. Bei der kleinsten Provokation castet Java nach int zurück, was sich bei einer Operation mit ausschließlich Bytes als Operanden nicht unbedingt erschließt.

Nachtrag:
Daß alle Datentypen in Java per Definition mit Vorzeichen sind, finde ich hingegen OK und hat mich bei meiner FPGA-Geschichte damals nicht weiter gestört. Wenn man unbedingt von 0-255 rechnen müssen können will...naja, casteste halt nach short oder int. Ist halt so. Was willste machen...und die Geräte, auf denen eine JVM läuft, sind normalerweise nicht so knapp mit Speicher alsdaß solche Optimierungen da allzuviel bringen. Und selbst wenn nicht genug Speicher da ist, macht das Javaprogramm den Kohl sicherlich auch nicht mehr fett.

Nachtrag 2:
Was mir an Java - ganz im Gegensatz zu C, wo man die Freiheit zu fast jeder Schweinerei hat - so gut gefällt, ist, daß gewisse Fehler einfach nicht mehr oder nur schwer gemacht werden können. Wieviele Unfälle sind schon passiert, weil man einen Wert >127 in ein signed Byte schreiben wollte? Ist deshalb nichtmal sogar eine Arianerakete abgeschmiert?

Nachtrag 3:
Stimmt nicht ganz, das mit der Ariane 5 war ein anderes Problem (64Bit Double in 16Bit Integer reindrücken wollen mit Operand Error Exception).
 
Zuletzt bearbeitet:
die Geräte, auf denen eine JVM läuft, sind normalerweise nicht so knapp mit Speicher alsdaß solche Optimierungen da allzuviel bringen. Und selbst wenn nicht genug Speicher da ist, macht das Javaprogramm den Kohl sicherlich auch nicht mehr fett.
Solche Optimierungen würden sowieso nur 6 Byte bringen (zwei Byte-Operanden, die statt 1 dann jeweils 4 Byte brauchen), und das auch nur während der Rechenoperation, und auch nur dann, wenn der 32bit-Support emuliert werden muss.

Direkter Support für Rechenoperationen mit Bytes in der JVM dürfte deutlich mehr Speicherplatz brauchen.
 
Ohnehin wäre direkte Byteunterstützung mit ziemlicher Wahrscheinlichkeit nur dann sinnvoll, wenn diese Unterstützung direkt an die Hardware weitergegeben werden kann. Wenn die JVM selber Byteoperationen mit "echten" Bytes durchführen würde, das hardwareseitig aber sowieso wieder in ein 32-Bit-Integer gecastet werden muß, dann ist das ja offenkundig Blödsinn.

Ich hab STM32 bisher nur aus C-Sicht programmiert und mich mit den einzelnen Registern nur soweit beschäftigt wie nötig um die Hardware zu konfigurieren, aber aus dem Bauch heraus würde ich mal sagen daß 16-Bit die minimale Registerbreite ist. Jedes Konfigurationsregister ist da wenigstens 16-Bit breit, öfter auch 32 (ist ja eine 32-Bit-Architektur), auch wenn da manchmal nur zwei oder gar ein Bit belegt ist.

Daher könnte ich mir sehr gut vorstellen, daß moderne CPUs, die ja schon seit Jahren 64-Bit-Operationen unterstützen, allerhöchstens noch 32-Bit-Operationen nativ unterstützen - alles darunter wird gnadenlos nach 32-Bit-Datentyp gecastet.
Eigentlich würde ich mich sehr wundern, wenn mein AMD A7, auf dem ich gerade unterwegs bin, tatsächlich noch hardwareseitig 16-Bit-Operationen durchführt. Das würde nähmlich dynamische Ressourcenverwaltung - und damit den Bau und Funktion von Betriebsystemen - erheblich erschweren und verlangsamen. Von acht Bit fange ich da gar nicht erst an.
 
Aktuelle 64-bit x86 CPUs zumindest unterstützen nach wie vor 8-bit, 16-bit, 32-bit und 64-bit Operationen. Allerdings spielt es keine Rolle, welche davon man wählt, da zumindest für integer-arithmetik und bitweise Operationen alle nur 1 Clockzyklus brauchen. Die ALU in solchen CPUs macht halt einfach nur 64-bit Operationen und maskiert bei kleineren Registerbreiten dann einfach die höheren Bits weg.
Es ist wirklich absolut irrelevant und verbraucht auch nicht mehr "Speicher", wenn man byte, short, int oder long als Methodenoperanden verwendet (vorausgesetzt, man verwendet eine moderne JVM und einen modernen Prozessor).
Zum Beispiel kann man auch ein 64-bit Register nicht "gleichzeitig" für zwei 32-bit Operationen verwenden, da zumindest bei x86 alle Operationen immer auf den niedrigwertigen "Prefixen" eines Registers definiert sind, z.B. ADD: https://c9x.me/x86/html/file_module_x86_id_5.html
Hier kann man die niedrigen 8-bit, 16-bit oder 32-bit eines Registers für Addition verwenden, aber eben keinen anderen "Teil" davon.
 
Zuletzt bearbeitet:
Was mir an Java - ganz im Gegensatz zu C, wo man die Freiheit zu fast jeder Schweinerei hat - so gut gefällt, ist, daß gewisse Fehler einfach nicht mehr oder nur schwer gemacht werden können. Wieviele Unfälle sind schon passiert, weil man einen Wert >127 in ein signed Byte schreiben wollte?
Da sehe ich in Java die größere Gefahr, weil sich byte und int durch den automatischen Cast (scheinbar) völlig anders verhalten.

Schauen wir uns mal an, wie int funktioniert:
Java:
int v = 0xff000000;
int out = v >> 1;
System.out.println(out);
OK, wer hier den Wert 0x7f800000 erwartet, der wird schon einmal vom signed shift right enttäuscht: 0xff800000 kommt hier raus.

Aber, man wird ja schlauer, also nochmal:
Java:
int v = 0xff000000;
int out = v >>> 1;
System.out.println(out);
Wunderbar: Wert halbiert.

So, jetzt machen wir das mal mit byte:
Java:
byte v = (byte)0xff;
byte out = (byte)(v >> 1);
System.out.println(out);
Wie erwartet: 0xff. Jetzt mal den richtigen shift operator verwenden:
Java:
byte v = (byte)0xff;
byte out = (byte)(v >>> 1);
System.out.println(out);
-1...

Das v wird erstmal zu einem int erweitert, aus -1 wird -1, d. h. alle Bits gesetzt, da ist es dann natürlich egal, welchen Shift-Operator man verwendet. Um das zu verhindern, muss man das byte zuvor in einen vorzeichenlosen Wert wandeln:
Java:
byte v = (byte)0xff;
byte out = (byte)((v & 0xff) >>> 1);
System.out.println(out);

Da gibt es in Java doch ein wenig mehr Fallstricke als in C:
C:
    unsigned char value = 0xff;
    printf("%d\n", value >> 1);
 
Zuletzt bearbeitet:
Das ist schon richtig, nur macht das jetzt für das Beispiel auch keinen Unterschied: byte in Java ist und bleibt grausam 🙂
 

Zurück
Oben