Integer in 4 Bytes zerlegen - Wie?



  • Hi, ich bin gerade am Auslesen von Level-Dateien für ein Spiel. Die Daten für die Vertices habe ich dabei schon gelesen.

    Nun habe ich die Koordinaten x, y und z (zusammen 12 Bytes). Sie alle sind Integer. Da diese Koordinaten aber überhaupt keinen Sinn ergeben, habe ich auf einer Website herausgefunden, wie ich zu den wirklichen Koordinaten komme.

    Zuerst muss ich jede Koordinate in ihre Bytes zerlegen (Byte 0-3) und dann folgendes rechnen:

    x=byte0+256*byte1+(byte2+256*byte3)/65536

    Das ganze geht mit y und z genauso. Jetzt ist nur die Frage: wie mache ich das?

    Bitte am besten einen kleinen Beispiel-code.
    Vielen Dank!



  • So:

    int a = value & 0xff;
    int b = ( value >> 8 ) & 0xff;
    int c = ( value >> 16 ) & 0xff;
    

    In a, b und c stehen dann die Koordinaten.



  • Einzelne Bytes kann man leicht mit union ansprechen:

    union coord{
      int asInt;
      unsigned char asChar[4];
    };
    
    coord x;
    x.asInt = 14;
    unsigned char n = x.asChar[0];
    


  • Fellhuhn schrieb:

    Einzelne Bytes kann man leicht mit union ansprechen:

    union coord{
      int asInt;
      unsigned char asChar[4];
    };
    
    coord x;
    x.asInt = 14;
    unsigned char n = x.asChar[0];
    

    das gibt laut standard "undefined behavior". man darf nur das union-member lesen, in welches man vorher geschrieben hat. die meisten compiler machens aber wohl so, dass es klappt.



  • fellhund schrieb:

    das gibt laut standard "undefined behavior". man darf nur das union-member lesen, in welches man vorher geschrieben hat. die meisten compiler machens aber wohl so, dass es klappt.

    Kann das nicht nur zu undefiniertem Verhalten führen, weil folgende Bedingung nicht garantiert ist?

    sizeof(int) == 4 * sizeof(char)
    

    Das Problem hat man bei Bitschiebereien nämlich auch.



  • Nexus schrieb:

    Kann das nicht nur zu undefiniertem Verhalten führen, weil folgende Bedingung nicht garantiert ist?

    sizeof(int) == 4 * sizeof(char)
    

    Das Problem hat man bei Bitschiebereien nämlich auch.

    Deshalb würde man dann ja auch int32_t verwenden



  • Das heisst, das undefinierte Verhalten aufgrund von Lesen von anderen union -Membern als der geschriebenen bestünde weiterhin?



  • ich denke mal, das undefinierte Verhalten rührt daher, dass Union nicht garantieren kann, dass alle Member gleich groß sind.

    Speichert man einen Wert in einen char und holt in sich über ein int wieder raus, dann braucht man sich nicht zu wundern, dass ein anderer Wert drinsteht. Andersrum ist es ja noch schlimmer

    Oder was rechtfertig das undefinierte Verhalten?



  • Es ist ein rein theoretisches Problem.
    In der Praxis funktioniert die Union Methode.



  • Bei der Methode mit der Union kommt ins Spiel, wie hat die Maschine den int32_t abgespeichert?

    littel endian oder big endian?

    Deshalb ist die Methode:

    David_pb schrieb:

    So:

    int a = value & 0xff;
    int b = ( value >> 8 ) & 0xff;
    int c = ( value >> 16 ) & 0xff;
    

    ...

    allgemeingültiger und besser. 😉



  • Wilma schrieb:

    Bei der Methode mit der Union kommt ins Spiel, wie hat die Maschine den int32_t abgespeichert?

    littel endian oder big endian?

    Deshalb ist die Methode:

    David_pb schrieb:

    So:

    int a = value & 0xff;
    int b = ( value >> 8 ) & 0xff;
    int c = ( value >> 16 ) & 0xff;
    

    ...

    allgemeingültiger und besser. 😉

    Wieso?



  • Ein int32_t hat immer die Bits 0 bis 31 - ob littel oder big endian gespeichert, spielt beim Schieben keine Rolle.



  • Wilma schrieb:

    Ein int32_t hat immer die Bits 0 bis 31 - ob littel oder big endian gespeichert, spielt beim Schieben keine Rolle.

    Und int32_t hat auch immer die Bytes 0-3
    egal ob little big oder median gespeichert...



  • Und warum nicht "long" anstatt "int32_t"?



  • Frage1 schrieb:

    Und warum nicht "long" anstatt "int32_t"?

    weil du einen 4 byte breiten typen haben willst und long wenn du pech hast 7,3 milliarden bytes groß ist?



  • So ne Kacke aber auch, ich dachte "long" ist immer 4 Bytes lang, garantiert das der Standard nicht?



  • Nein, siehe dazu auch diesen Thread.



  • Shade Of Mine schrieb:

    Wilma schrieb:

    Ein int32_t hat immer die Bits 0 bis 31 - ob littel oder big endian gespeichert, spielt beim Schieben keine Rolle.

    Und int32_t hat auch immer die Bytes 0-3
    egal ob little big oder median gespeichert...

    Ich verstehe weder die "Warum?"-Frage ein paar Posts vorher noch diese Aussage.

    Little Endian: LSB 2B 3B HSB
    Mapt man das direkt auf Bytes, dann bekommt man für byte[0] eben das LSB
    Big Endian: HSB 3B 2B LSB
    Mapt man das direkt auf Bytes, dann bekommt man für byte[0] eben das HSB

    (uint32_t >> 24) && 0xFF liefert hingegen immer das HSB. Egal, ob dem Wert Little- oder Big Endian zugrunde liegt.



  • Danke, interessanter Thread @Nexus.

    Eine Frage aber noch:
    "int32_t" ist auf einem 32bit System gleich "int" oder "long" nehme ich an.
    Und auf einem 64bit System? short? Ist "short" auf einem 64bit system 32bit breit?



  • Kapier ich nicht. Kannst du mir das bitte mal vorrechnen?
    Irgendwie sehe ich den Unterschied nicht...


Anmelden zum Antworten