signed/unsigned

Status
Nicht offen für weitere Antworten.
G

GnuJ

Gast
Hallo!

Bin mir nicht sicher ob das in die Netzwerk 'Abteilung' oder hier hingehört :O

Zum Problem selber:
Ich versuche derzeit einen Gnutella Client in Java schreiben- klappt auch recht gut bis jetzt :?
Nun bin ich aber auf folgendes Problem gestoßen:

Ich erstelle zB eine Ping Nachricht- welche intern halt einfach aus bytes Zusammengestoppelt wird. Nun kommt letztendlich ein byte[] raus weöches zB so aussieht:
UUID Payload Descriptor TTL Hops Payload Length
byte[16] byte byte byte byte[4]

Dies ergibt also ein byte[23]- so weit so gut- nun muss ich das ganze über das Netzwerk ausgeben (bzw bei anderen Messages wie Pong einlesen)- hier werden aber überall SIGNED byte benötigt- dem zu folge versteht mich niemand
:oops:

Nun könnte ich ja alle Werte als short[] oder int[] speichern- nur wie schreib ich die denn auf das Netzwerk- wenn dort ein byte Array erwartet wird? ???:L
 

SnooP

Top Contributor
hmm... sehr komisch - was passiert denn, wenn du eine integer-variable in ein byte castest. Wenn du beispielsweise signed ne 255 speicherst ist dies in java das gleiche wie ne -1 (signed). Aber wenn du nen short hast wo die 255 drin steht und die in das byte castest erstellt er dort doch automatisch die (auch fürs netzwerk dann) korrekte -1. Schwieriger wird das ganze höchstens beim wieder rauslesen... aber das senden sollte nicht das problem sein.
 
G

GnuJ

Gast
ah- k danke schonmal für die schnellen Antworten!

Also wenn ich das richtig verstanden habe- kann ich ganz normal weiter intern mit meine bytes hin und herrechnen oder was auch immer :)
und dieses byte[] dann einfach auf das "Netzwerk" rausschreiben- und ein C client oder was auch immer wird das korrekt empfangen ???:L (also korrekt einlesen können?)

aber was passiert wenn ich Daten bekomm- kann ich die also ebenfalls einfach per byte = read() einlesen und wieder schön damit arbeiten (sprich er übernimmt die "Konvertierung oder was auch immer" selber?
 

0xdeadbeef

Top Contributor
Naja, mit Bytes kann man in Java eigentlich gar nicht rechnen. Sobald man irgendwas damit macht, werden sie in ein "int" konvertiert. Gleiches gilt übrigens für short und char.
Also z.B.

Code:
        byte a,b;

        a= (byte)0xff;
        b = 0;

        int i = a + b;              // falsch: Ergebnis ist -1 + 0 -> -1
        int j = (a + b) & 0xff;  // richtig: (-1 & 0xff) -> 0xff

Wenn man natürlich das Ergebnis wieder in byte "zurückcasted", dann ist es vom Binärwert her auch ok.
In die Hose geht das ganze halt genau dann, wenn das Byte zwecks Ausgabe in ein "int" konvertiert wird (evtl. auch implizit). Vermutlich liegt genau hier Dein Problem...
 

SnooP

Top Contributor
GnuJ hat gesagt.:
aber was passiert wenn ich Daten bekomm- kann ich die also ebenfalls einfach per byte = read() einlesen und wieder schön damit arbeiten (sprich er übernimmt die "Konvertierung oder was auch immer" selber?

ne... eben grad nicht, da du halt wenn du die bytes empfängst diese von java natürlich als signed interpretiert werden. Das ist ja aber nicht weiter schlimm, da du ja die Konvertierung kennst, d.h. du musst einfach eine convert-Methode schreiben, die die unsigned-Daten entsprechend verschiebt.
Code:
	public static int convert(byte rcv) {
		return (rcv+256)&0xFF;
	}
Mein Vorposter hats im Prinzip schon angedeutet... weiß jetzt auch nicht, ob das besonders schick ist... aber es sollte funktionieren ;) - er addiert halt immer die 256 hinzu.. so dass bei 2er Komplement-Zahlen (-1, -2,...,-126) der "richtige" signed Wert herauskommt, während Zahlen die über 256 hinaus gehen und im int natürlich angezeigt werden würden durch die Maske 0xFF (jenau ein byte) begrenzt werden.

hth
 

byte

Top Contributor
Oder einfach: ;)

Code:
	public static int convert(byte rcv) {
		return (int) rcv & 0xFF;
	}
 

0xdeadbeef

Top Contributor
SnooP hat gesagt.:
Mein Vorposter hats im Prinzip schon angedeutet... weiß jetzt auch nicht, ob das besonders schick ist... aber es sollte funktionieren ;) - er addiert halt immer die 256 hinzu.. so dass bei 2er Komplement-Zahlen (-1, -2,...,-126) der "richtige" signed Wert herauskommt, während Zahlen die über 256 hinaus gehen und im int natürlich angezeigt werden würden durch die Maske 0xFF (jenau ein byte) begrenzt werden.
hth
Der "Vorposter" hat in einem Beispiel zwei Bytes addiert, von denen das eine zufällig 0xff war. Das ist aber natürlich nicht Teil der Konvertierung, wie das Beispiel deutlich zeigt.

Das Problem ist, daß bei der Umwandlung eines Bytes in eine Integerzahl die oberen Bits vorzeichengerecht erweitert werden. Steht also im oberten Bit des Bytes eine 1 (Sign = negativ), dann werden neu hinzugekommenen oberen Bits des Integers ebenfalls mit 1en augefüllt.
0xfe -> 0xfffffffe

Während das Byte noch +254 oder -2 bedeuten kann, ist es nach der automatischen Konvertierung ganz sicher eine -2.

Abhilfe schafft also, wie ja bereits in meinem ersten Posting gezeigt, die untersten 8 Bit auszumaskieren:

0xfffffffe & 0xff = 0x000000fe

Jetzt sind die neu hinzugekommenen Bits also mit 0ern aufgefüllt und die Zahl ist positiv.

Zusammengefaßt kann man sagen: Java interpretiert Variablen vom Type byte oder short immer als vorzeichenbehaftet, wenn sie in Integer konertiert werden. Eine automatische Konvertierung erfolgt bei jedem Vergleich, bei jeder mathematischen Operation und u.U. bei der Ausgabe. Wenn man ein Byte also als vorzeichenlos interpretiert haben möchte, muß die unteren 8 Bits per "& 0xff" abschneiden. Das funktioniert im Übrigen nur, weil der "&"-Operator selber zu einer Konvertierung nach int führt.
 

byte

Top Contributor
0xdeadbeef hat gesagt.:
Wenn man ein Byte also als vorzeichenlos interpretiert haben möchte, muß die unteren 8 Bits per "& 0xff" abschneiden. Das funktioniert im Übrigen nur, weil der "&"-Operator selber zu einer Konvertierung nach int führt.

Das ist genau der Punkt. Um das mal in Zahlen auszudrücken:


* 0xFF als Byte in Binärdarstellung: 11111111
* entspricht als int der -1, da Bit 8 das Vorzeichen ist
*-1 in 32 Bit (int) Binärdarstellung 11111111111111111111111111111111
* & 0xFF liefert genau die letzten 8 Bit, diesmal ist Bit 8 jedoch NICHT das Vorzeichen, da int 32 Bit hat und daher Bit 32 das Vorzeichen Bit ist

Code:
11111111111111111111111111111111  (-1   )
00000000000000000000000011111111  (&0xFF)
--------------------------------
00000000000000000000000011111111  (= 255)
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen

Neue Themen


Oben