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 00000010Bitfolge um zwei Bit nach links schieben:
00000001 << 2 00000100142
Wenn du jetzt aber zu weit schiebst geht alles was links rausgeschoben wird verloren:00000001 << 8 00000000Das 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 = 1Der 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 --------------- 001111111100110Lektion 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 => 10001110bDann musst du diese Werte einfach aneinanderreihen:
00000000 00000000 00000000 10001110 << 24 10001110 00000000 00000000 0000000000000000 00000000 00000000 11110000 << 16 00000000 11110000 00000000 0000000000000000 00000000 00000000 10011101 << 8 00000000 00000000 10011101 0000000000000000 00000000 00000000 10111000Nachdem 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 10111000Der 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 = eaxEs 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
