Verständnisprobelm



  • Hallo zusammen

    Ich hab in einem Tutorial in dem es darum geht Infos einer Windows Bitmap datei zu entnehmen eine funktion gefunden die wie folgt lautet:

    int toInt(const char* bytes) {
    		return (int)(((unsigned char)bytes[3] << 24) |
    					 ((unsigned char)bytes[2] << 16) |
    					 ((unsigned char)bytes[1] << 8) |
    					 (unsigned char)bytes[0]);
    }
    

    Das die Funktion aus den 4 eingelesenen Chars die die Größer der Bitmap darstellen sollen ein Integer macht der dann der Größe in Byte entspricht is mir soweit klar. Was ich auch soweit verstanden hab is das die 8,16 und die 24 die jeweiligen chars an die richtige posizion verscheiben. Nur versteh ich nicht ganz wie ich ein char um 8,16 oder 24 stellen verscheiben kann ohne das was dabei verlohren geht. Ich glaub mein Problem liegt darin das ich nicht genau weis was dort intern vorgeht und in welcher reihenfolge das abläuft.
    Ich hoffe ihr könnt mir helfen das zu verstehen. 😃

    edit: wie wird ein unsigned char gegenüber einem normalen char von den bitoperatoen behandelt?



  • Hi!

    Der links-Shift Operator verschiebt dein char für dich und wenn du nicht zu weit schiebst geht auch nichts verloren.

    Lektion 1, Shiften

    Hier wird die Bitfolge um ein Bit nach links geschoben:

    00000001 << 1 
    00000010
    

    Bitfolge um zwei Bit nach links schieben:

    00000001 << 2
    00000100
    

    142
    Wenn du jetzt aber zu weit schiebst geht alles was links rausgeschoben wird verloren:

    00000001 << 8
    00000000
    

    Das bedeutet die Bits rotieren nicht, sondern werden nach links aus der Bitstruktur geschoben. in dem Fall brauchst du einen größeren Datentyp um verluste zu vermeiden.

    Lektion 2, Bitweises ODER

    Wenn zwei Bits per Bitweisem ODER (|) verknüpft werden hat das folgende Auswirkung:

    0 | 0 = 0
    0 | 1 = 1
    1 | 0 = 1
    1 | 1 = 1
    

    Der ODER Operator achtet also darauf das mindestens ein Bit gesetzt wurde. Ist dies der Fall ist das resultierende Bit ebenfalls gesetzt (1).

    Ein "komplexeres" Beispiel:

    001010111100010 |
    001101001000110
    ---------------
    001111111100110
    

    Lektion 3, aus 4 Bytes 1 Integer

    Angenommen (ist bei dir wahrscheinlich so) dein char hat 8 Bit und dein int 32. Dann passen in dein int genau 4 chars (32/8=4). Diese 4 char Werte hast du ja bereits, nun musst du sie nurnoch so aneinanderreihen das sie deine 32 Bit (für den integer) füllen.

    Angenommen du hast deine 4 Bytes haben folgende Werte:

    bytes[ 0 ] = 184 => 10111000b
    bytes[ 1 ] = 157 => 10011101b
    bytes[ 2 ] = 240 => 11110000b
    bytes[ 3 ] = 142 => 10001110b
    

    Dann musst du diese Werte einfach aneinanderreihen:

    00000000 00000000 00000000 10001110 << 24
    10001110 00000000 00000000 00000000
    
    00000000 00000000 00000000 11110000 << 16
    00000000 11110000 00000000 00000000
    
    00000000 00000000 00000000 10011101 << 8
    00000000 00000000 10011101 00000000
    
    00000000 00000000 00000000 10111000
    

    Nachdem du die Bitfolgen neu positioniert hast kannst du alle per logischen UND verknüpfen. Da bei jeder Bitfolge nur ein Oktett gesetzt ist, welches bei allen anderen NICHT gesetzt ist verändert sich an den einzelnen Oktetten nichts.

    10111000 00000000 00000000 00000000
    00000000 11110000 00000000 00000000
    00000000 00000000 10011101 00000000
    00000000 00000000 00000000 10111000 |
    -----------------------------------
    10001110 11110000 10011101 10111000
    

    Der Resultierende int-Wert (unsigned) ist also: 2398133688
    Da du aber ein int als Datentyp verwendest und dieses ein signed (Vorzeichenbehafteter) Datentyp ist, hast du nicht die vollen 32 Bit für deinen Wert zur verfügung. Das Bit 31 ist das "sign-Bit". Ist dieses Bit gesetzt so wird davon ausgegangen das deine Zahl im Negativen Bereich liegt.

    Der Wert ist also in deinem Fall: -1896833608

    Viele Grüße



  • Erstmal Vielen dank David für die ausfürliche erklährung dadurch versteh ich schon ein ganzen stück mehr von der Funktion. Leider gibt es ein punkt den ich immer noch nicht so recht verstehe.
    Damit ihr wisst wo ihr ansetzen müsst sag ich euch was soweit aus meiner sicht passiert.

    (unsigned char)bytes[1] << 8) | (unsigned char)bytes[0])
    

    Also angenommen byte[0] ist 00010110 und byte[1] ist 01100001 dann wird byte[1] um 8 verschoben dann sollte es doch eigentlich 00000000 sein es ist doch immer noch ein char also 1 byte lang und genau da liegt das verständnisproblem ich versteh nicht warum aufeinmal 2 oder wie von David beschreiben sogar 4 bytes eines chars betrachtet werden können.

    Ich hab mir 2 sachen überlegt die mir einleuchten würden wenn ich wüsste warum das so passiert. Einmal denke ich das das (int) da schon die finger im spiel haben könnte.
    Und das andere was ich für warscheinlicher halte das die überstehenden bits erst zu einer gewissen zeit verworfen werden .. z.b. zuweisung.

    Ich hoffe jemand von euch kann mir daruf eine Antwort geben.

    Gruß Yumi



  • Es geht eher um die 32 Bit des Zieldatentyps, die sind nämlich vorhanden:

    int main()
    {
    	char x = 0xff;
    	char y = 0x7f;
    
    	int z = ( x << 8 ) | y;
    }
    

    Wird zu:

    mov [ebp-05], FF ; char x = 0xff
    mov [ebp-11], 7f ; char y = 0x7f
    movsx eax, byte ptr [ebp-05] ; x in register eax
    shl eax, 08 ; x << 8
    movsx ecx, byte ptr [ebp-11] ; y in register ecx
    or eax, ecx ; eax = eax | ecx
    mov dword ptr [ebp-20], eax ; z = eax
    

    Es wird erst Kopiert und schon kannst du die volle Bandbreite (deine 32 Bit) verwenden. Mit anderen Worten, du schreibst ja nicht bytes[ i ] = bytes[ i ] << 8; int x = bytes[ i ];



  • Vielen dank ich glaub jetzt hab ichs verstanden 🙂


Anmelden zum Antworten