2 Byte Ziffer zu Integer wandeln
-
Hallo,
ich kriege über einen Socket 2 Byte, die eine fortlaufende Zahl darstellen sollen.
Diese Zahl befindet sich jetzt in einem 2-Byte langen Buffer, praktisch so:[ 123 ] [ 214 ]
Das wäre jetzt zusammen betrachtet 123214. Allerdings würde ich diesen Wert jetzt gerne als long haben. Falls das ganze in nur einem Byte untergebracht wäre, d.h. 0-255, wäre das ganze kein Problem, aber die 2 Byte machen mir Kopfschmerzen.
Die bisherige Bitshift-Lösung sah so aus:
act_size = (*ackbuf++ << 8); act_size &= 0xff00; act_size += (*ackbuf++ & 0x00ff);
was soweit auch funktionierte, zumindest auf meinem Little Endian Core 2. Jetzt sitze ich hier allerdings an einem Motorola G4 der Big Endian verwendet und das ganze funktioniert nichtmehr
Ich habe jetzt versucht die bytes einzeln rauszuziehen und mit atoi umzuwandeln, allerdings bringt mir das auch nichts wenn die Werte über 255 hinaus gehen und so das 2. Byte mit einbezogen werden muss...
Ich hoffe jemand hat eine Idee wie man sowas portabel lösen kann, ich bin hier langsam aber sicher am verzweifeln
-
Hi Bruder !
->
unsigned char _2b[2]; // Two byte buffer. long num; // Converted value. // hex dec _2b[0] = 0x7b; // 123 _2b[1] = 0xd6; // 214 num = _2b[0] * 1000; num += _2b[1]; // num = 123214 // andreasrum: num = _2b[1] * 1000; num += _2b[0]; // num = 214123
-
Hi,
danke erstmal für deine Antwort.Leider funktioniert der Ansatz nicht wenn z.B. 256(dezimal) das erste mal auftritt, er würde dann 1000 statt den erwarteten 256 erzeugen.
Das erste Byte ([0]) müsste dann zum ersten mal beschrieben werden bzw. auf 1 springen bei der Gesamtzahl 256 (100000000(dual)), d.h. das ganze würde dann so aussehen: [00000001][00000000].Allerdings habe ich beim testen von deinem Ansatz bemerkt dass der PowerPC die Zahlen tatsächlich dort platziert wo man es erwarten würde, d.h. die 2 Byte von "hinten" auffüllt, so: [000][001], [000][010], [000][011] usw.
-
So, auf die einfachsten Lösungen kommt man natürlich nie
Ich habe jetzt einfach einen Zeiger auf einen uint16 auf die betreffende Speicherstelle zeigen lassen, et voila, es funktioniert. uint16 weil der Datentyp unsigned ist, d.h. das erste bit wird nicht als Vorzeichenbit interpretiert und 16 weil es genau 16 bit (=2 byte) sind, also exakt passend für meine Zahl.
Ich glaube damit wäre auch das Problem der Endianess gelöst, zumindest funktioniert der Code jetzt auf dem G4 und auf dem Core 2.
uint16 *act_size; act_size=(uint16*)&ackbuf[2];
-
Herr jth schrieb:
So, auf die einfachsten Lösungen kommt man natürlich nie
falls dein array aber nicht an einer geraden adresse beginnt (was bei char-arrays sowieso nie garantiert ist), könnte deine CPU mit einem 'bus-error' aussteigen, wenn du versuchst einen 2-byte wert von einer ungeraden adresse zu lesen. nicht wenige CPU's mögen sowas überhaupt nicht. was spricht eigentlich gegegen:
uint16 act_size = ackbuff[2] + 256*ackbuff[3];
bzw.
uint16 act_size = 256*ackbuff[2] + ackbuff[3];
(je nach endianess des 16-bit wertes in 'ackbuff')
das sollte portabel sein daher fast überall stressfrei funzen.
-
endianess-freak schrieb:
Herr jth schrieb:
So, auf die einfachsten Lösungen kommt man natürlich nie
falls dein array aber nicht an einer geraden adresse beginnt (was bei char-arrays sowieso nie garantiert ist), könnte deine CPU mit einem 'bus-error' aussteigen, wenn du versuchst einen 2-byte wert von einer ungeraden adresse zu lesen. nicht wenige CPU's mögen sowas überhaupt nicht. was spricht eigentlich gegegen:
uint16 act_size = ackbuff[2] + 256*ackbuff[3];
bzw.
uint16 act_size = 256*ackbuff[2] + ackbuff[3];
(je nach endianess des 16-bit wertes in 'ackbuff')
das sollte portabel sein daher fast überall stressfrei funzen.
Was soll man sagen, du hast recht.
Hab mich mal grob über Alignment schlau gemacht, und die Lösung oben ist dann wohl tatsächlich die bessere. In /usr/include/asm/byteorder.h scheinen ein paar ganz nützliche Konstanten definiert zu sein mit denen man rausfinden kann ob man auf einer Big- oder Little-Endian Maschine ist. Ich denke das lässt sich ganz gut vom Präprozessor lösen.
#ifdef _LITTLE_ENDIAN uint16 act_size = 256*ackbuff[2] + ackbuff[3]; #endif
o.Ä, mal schauen wie das im Detail funktioniert.