Word aus 2 Bytes basteln



  • Hab mir das ganze jetzt nochmal angekuckt und wenn ich das nicht falsch verstehe ist Big Endian doch so aufgebaut:

    0....8....16

    Das heißt ich muss doch die least significant bits reinpacken und nach links verschieben dann einfach die oberen mit rein odern.

    LZSWORD w_retValue = b_low_i << 8 | b_high_i;

    Oder etwa nicht?

    bzw wenn ich das kürzer schreiben wollte:

    return ((LZSWORD) b_low_i << 😎 | b_high_i;

    Lieg ich da falsch und übersehe was?



  • m00ni schrieb:

    Hab mir das ganze jetzt nochmal angekuckt und wenn ich das nicht falsch verstehe ist Big Endian doch so aufgebaut:
    ...
    Lieg ich da falsch und übersehe was?

    Die Endianess einer CPU besagt ausschließlich wie die CPU ein Wort im Speicher ablegt. Big Endian heißt Most Significant Byte zu erst, Least Significant Byte zuletzt. Das macht sich für den Programmier dann und nur dann bemerkbar, wenn er ein Wort byte weise liest oder schreibt. Auch wenn er Assembler benutzt.

    wort << 8;  // verschiebe wort um 8 bit richtung höherwertiges byte
    

    macht immer das gleiche egal ob big oder little endian. Daher erzeugt mein erstes Beispiel immer das native format, das zweite immer das jeweils andere. Egal mit welchen Compiler das übersetzt und mit welcher CPU das dann ausgeführt wird. Oder anderes Beispiel

    wort = 1;
    wort << 8;
    printf( "%d\n", wort );
    

    ergibt immer 256.

    mfg Martin



  • Endianes wird auf Byteebene betrachtet und hat erstmal nichts mit Bits zu tun.

    Nimm das Wort 0x1234 an SPeicherstelle 1000. Dann steht bei BigEndian in 1000: 0x12 und in 1001: 0x34.
    Bei LittleEndian steht in 1000 die 0x34 und in 1001 die 0x12.

    Oder bei long 0x12345678 ->
    Lit : 1000: 0x78 0x56 0x34 0x12
    Big : 1000: 0x12 0x34 0x56 0x78



  • m00ni schrieb:

    die Bytes haben Big Endian format und das Word soll eben nach der Umwandlung auch Big Endian sein.

    Bytes selbst haben kein Endian, nur eine Reihung dieser.
    Da du Bigendian brauchst, kannst du den Unix-Standard POSIX benutzen, z.B.

    #include <arpa/inet.h> /* unter win auch winsock2.h */
    
    unsigned short bigend_word(unsigned char hi,unsigned char lo)
    {
      return htons(hi<<8|lo);
    }
    

    htons kümmert sich dann um den Rest.



  • mgaeckler schrieb:

    supertux schrieb:

    so?

    ...(((LZSWORD) b_low_i) >> 8)...
    }
    

    Was passiert, wenn ich ein Byte um 8 Bit nach rechts shifte?

    eigentlich solltest du dann 0 bekommen, deshalb habe ich es explizit auf einen Datentype gecastet, der mehr Bits enthält.

    m00ni schrieb:

    Hab mir das ganze jetzt nochmal angekuckt und wenn ich das nicht falsch verstehe ist Big Endian doch so aufgebaut:

    0....8....16

    Das heißt ich muss doch die least significant bits reinpacken und nach links verschieben dann einfach die oberen mit rein odern.

    LZSWORD w_retValue = b_low_i << 8 | b_high_i;

    Oder etwa nicht?

    ja, siehe meinen letzten Post. Wobei, wenn b_low_i nur 8-Bit breit ist, dann ist b_low_i << 8 sehr wahrscheinlich 0.



  • Ich haette 'nen union genommen.


  • Mod

    knivil schrieb:

    Ich haette 'nen union genommen.

    Strenggenommen aber undefiniertes Verhalten. Natürlich wird jede reale Implementierung das machen, was du hier erwartest, aber warum ohne Not Undefiniertes tun?



  • supertux schrieb:

    mgaeckler schrieb:

    supertux schrieb:

    so?

    ...(((LZSWORD) b_low_i) >> 8)...
    }
    

    Was passiert, wenn ich ein Byte um 8 Bit nach rechts shifte?

    eigentlich solltest du dann 0 bekommen, deshalb habe ich es explizit auf einen Datentype gecastet, der mehr Bits enthält.

    Wenn ich jetzt Dein Informatiklehrer wäre, würde ich sagen "Setzen 6". Bin ich aber nicht.
    1. Die Lösung mit 0 stimmt nur dann, wenn Du ein vorzeichenloses Byte hast. Bei einem vorzeichen behafteten Byte wird einfach das Vorzeichen nachgeschoben:

    -127 >> 8 = -1
    

    2. Meinst Du im Ernst, daß Dein cast aus Deinem 8 Bitwert einen 16 Bitwert zaubert? Pass auf: das passiert:
    10101010 gecastet wird zu 0000000010101010. So und jetzt stell Dir vor, das wird um 8 Bits nach rechts verschoben. Was haben wir dann?

    0000000000000000
    

    Dein cast hat also nichts, rein gar nichts gebracht. Bitte beachte, das Beispiel so gilt nur für vorzeichenlose Bytes.

    supertux schrieb:

    a, siehe meinen letzten Post. Wobei, wenn b_low_i nur 8-Bit breit ist, dann ist b_low_i << 8 sehr wahrscheinlich 0.

    Tut mir leid, schon wieder daneben. b_low_i wird automatisch zu einem int bzw. unsigned int gecastet. Es stehen damit 16 oder mehr Bits zur Verfügung und b_low_i << 8 wird daher dann und nur dann 0 wenn b_low_i schon 0 ist.

    mfg Martin



  • knivil schrieb:

    Ich haette 'nen union genommen.

    meinst Du sowas?

    union xyz
    {
       unsigned short  word;
       struct
       {
          unsigned char byte1, byte2;
       } endian;
    };
    

    Das ist nicht ungefährlich. Der Standard garantiert Dir nur, daß alle Datenfelder in einem struct in genau der Reihenfolge im Speicher erscheinen, wie sie auch in der Deklaration erscheinen. Der Compiler darf aber z.B. zwischen den Elementen beliebige Füllbytes einfügen.

    Der Union bringt Dir keinen nennenswerten Vorteil, daß es sich lohnt, dieses Risiko einzugehen.

    mfg Martin



  • Sicher, aber man kann ja mit sizeof nachpruefen. Aber da hier mit Endian argumentiert wird, haengt sowieso viel von aeusseren Umstaenden ab.

    Der Union bringt Dir keinen nennenswerten Vorteil, daß es sich lohnt, dieses Risiko einzugehen.

    Ich finde Bitschiften immer etwas verwirrend.



  • knivil schrieb:

    Sicher, aber man kann ja mit sizeof nachpruefen. Aber da hier mit Endian argumentiert wird, haengt sowieso viel von aeusseren Umstaenden ab.

    Der Union bringt Dir keinen nennenswerten Vorteil, daß es sich lohnt, dieses Risiko einzugehen.

    Ich finde Bitschiften immer etwas verwirrend.

    Ach ja? Und wie reagierst Du, wenn sizeof( word ) != sizeof( endian )?

    Was ist am Bitshift verwirrend? Grundregel: kümmere dich beim Bitshift nicht um die Endianess. Das macht der Prozessor für Dich. Einzig und allein die Vorzeichen sind wichtig.

    x << 1 ist das selbe wie x * 2
    x << 2 ist das selbe wie x * 4
    x << 3 ist das selbe wie x * 8

    u.s.w. u.s.f

    vieleicht hilft das, um die Bitshiftoperatoren zu verstehen.

    mfg Martin


  • Mod

    knivil schrieb:

    Sicher, aber man kann ja mit sizeof nachpruefen. Aber da hier mit Endian argumentiert wird, haengt sowieso viel von aeusseren Umstaenden ab.

    Der Union bringt Dir keinen nennenswerten Vorteil, daß es sich lohnt, dieses Risiko einzugehen.

    Ich finde Bitschiften immer etwas verwirrend.

    Aber die ganze Endianessgeschichte ist ohnehin unnötig, wenn man statt unions & Co lieber Bitshifterei benutzt.

    Und zu der obigen Castdiskussion: Denkt daran, dass die Datentypen während der Rechnung dank der integral promotion ohnehin vergrößert werden.



  • Wie portabel ist eigentlich dieser Code?

    struct Flag
    {
    	unsigned char f1 : 1;
    	unsigned char f2 : 1;
    	unsigned char f3 : 1;
    	unsigned char f4 : 1;
    	unsigned char f5 : 1;
    	unsigned char f6 : 1;
    	unsigned char f7 : 1;
    	unsigned char f8 : 1;
    };
    

    Nehmen wir an ich würde ein unsigned char über das Netzwerk verschicken. Wäre das portabel? Ist das struct portabel?


  • Mod

    Der interne Aufbau von bit-fields ist meines Wissens nach implementation defined, ich mag aber gerade nicht die entsprechende Stelle im Standard suchen und zitiere daher bloß aus dem Gedächtnis.



  • Und wenn ich einen unsigned char nehme und ihn manuell mit Bit Manipulationen manipuliere und über das Netzwerk versende. Wäre das portabel?


  • Mod

    reex schrieb:

    Und wenn ich einen unsigned char nehme und ihn manuell mit Bit Manipulationen manipuliere und über das Netzwerk versende. Wäre das portabel?

    Ziemlich. Es gibt ein paar exotische Systeme mit CHAR_BIT > 8, aber dies ist extrem selten.



  • SeppJ schrieb:

    reex schrieb:

    Und wenn ich einen unsigned char nehme und ihn manuell mit Bit Manipulationen manipuliere und über das Netzwerk versende. Wäre das portabel?

    Ziemlich. Es gibt ein paar exotische Systeme mit CHAR_BIT > 8, aber dies ist extrem selten.

    Das ist gut zu wissen. Diese exotischen Systeme sind für mich glücklicherweise egal. Vielen Dank für die Antwort 🙂


Anmelden zum Antworten