# Bitoperator "<<", was passiert genau dabei?



## astaluego (13. September 2005)

Hallo Zusammen

Ich hab folgenden Code erhalten:


```
output[x] = input[y] << 4;
```

was man weiss: x = 1, y=1, input[y] = 'A' 

Ich kann nicht verstehen oder gar vorstellen, wie das ablaufen sollte mit dem Linksverschieben der Bits. Denn eine Erklärung im Internet besagt:  Beim Links-Shift werden von rechts 0-Bits nachgeschoben, die links herausgeschobenen Bits gehen verloren. Wird mein Buchstabe 'A' in eine 8-Bit high-low zahl umgewandlet oder was? Und was passiert wenn ich nun um 4 Bits verschiebe?

gruss


----------



## vop (13. September 2005)

Also zur Info

Buchstaben sind nichts anderes als Zeichen in einer Tabelle
Der Buchstabe A befindet sich in dieser Tabelle an Position 65
Daher hat der Buchstab den Ordinalwert 65, was binär
10000001 entspricht (nämlich 64 + 1=65)
Wenn Du nun Bits herausschiebst, die dann wegfallen passiert folgendes
(bspw. 2 Bit rausschieben
10           [  000001 [ 00
zwei raus, sechs Bits bleiben,  zwei Nullen rechts rein

Es ergbit sich dann
 00000100 das ist dann dezimal 4

Alles klar?

vop


----------



## RedWing (13. September 2005)

> Wenn Du nun Bits herausschiebst, die dann wegfallen passiert folgendes
> (bspw. 2 Bit rausschieben
> 10 [ 000001 [ 00
> zwei raus, sechs Bits bleiben, zwei Nullen rechts rein


 
4 kommt da aber nur raus solange du dich im character Wertebereich
bewegst, im Integer Wertebereich kommt da ein andres Ergebniss raus...

@astaluego
Nachtrag zu meinem Vorposter:

Wenn du eine Zahl um ein Bit nach links verschiebst ist das eine 
Multiplikation der Zahl mit 2.
Nach rechts => Division der Zahl mit 2...

Gruß

RedWing


----------



## vop (13. September 2005)

@RedWing korrekt, guter Hinweis!


			
				RedWing hat gesagt.:
			
		

> 4 kommt da aber nur raus solange du dich im character Wertebereich
> bewegst, im Integer Wertebereich kommt da ein andres Ergebniss raus...



und Achtung:


			
				RedWing hat gesagt.:
			
		

> Wenn du eine Zahl um ein Bit nach links verschiebst ist das eine
> Multiplikation der Zahl mit 2.


Das gilt dann aber auch nur, wenn Du den richtigen Wertebereich beachtest ;-)
Bspw. im Characterbereich ( 1 Byte )
wird aus
11111111 mit <<
11111110
was in diesem Fall nicht einer Multiplikation mit 2 entspricht.

Nenne uns aber nun nicht Haarspalter....

vop


----------



## RedWing (13. September 2005)

> Das gilt dann aber auch nur, wenn Du den richtigen Wertebereich beachtest
> Bspw. im Characterbereich ( 1 Byte )
> wird aus
> 11111111 mit <<
> ...


Naja es enstspricht immer noch einer Division bzw Multiplikation nur das
dir ein paar Bits verloren gehen. 
Sprich die höchste Stelle geht verloren, wenn man auf den Wertebereich 
nicht achtet. Es kommt zum Informationsverlust.
Wenn du einen integer über seinen Wertebereich aufsummierst
wird die Operation trotzdem noch ne Addition bleiben nur das Ergebniss
wird falsch...

Aber wir wollen ja keine Haare spalten 

Gruß

RedWing


----------



## astaluego (14. September 2005)

Danke für die vielen Antworten. 
Das hat mich einbischen aufgeklärt. 
Ich befinde mich im Characterbereich trotzdem habe ich gewisse Probleme:

```
ByteToHalf(byte* abInput, int isize )
{
  byte abOutput[sizeof(abInput)];
  int  i,j;
  
  j = 0;
  for(i=0;i<isize;i++)
  {
    if((abInput[i] - 48) * (abInput[i] - 57) <= 0)      // 0 - 9
      abOutput[j] = abInput[i] - 48;                  
    else
      abOutput[j] = abInput[i] - 55;                    // A - F

    i++;
    abOutput[j] = abOutput[j] << 4;
....
  }
```

abInput ist einfach ein character-array(string "hallo" > charArray) welches in ein byte array umgewandelt wurde. Jetz bin ich mir nicht sicher was den genau in abInput steht da ich mich mit den Datentypen von C++ nie auseinandergesetzt habe. Zudem kommt noch der Faktor hinzu, dass ich das Zeug in C# umwandeln muss. In C# dürfen nur Zahlen also in meinem Fall die Dezimalzahl des Characters gespeichert werden. Wenn Ich jetz z.b das Character 'Y' in das abInput[x] speichern will muss ich Convert.ToByte(Convert.ToInt32('Y')) machen. Kommt es zum Verschieben von 4 Position eskaliert das ganze da 'Y' = 89 und 89 << 4 = 1424, ich kann aber in ein byte Array nicht mehr als 255 speichern darum bringt er auch den Fehler: Value was either too large or too small for an unsigned byte.
Zudem versteh' ich den Quellcode von oben überhaupt nicht. Meine Vermutung ist dass er auch die Dezimalzahlen im abInput hat und das irgendwie auf Hexwerte prüft (im Kommentar). Ich hoffe man kommt draus, was ich nun hier beschrieben hab. 

gruss


----------



## vop (14. September 2005)

Hi

 so wie ich den Quelltext verstehe, wird in abInput ein String erwartet, der einer Hexadezimalzahl entspricht und nur die Zeichen 'A' bis 'F' sowie '0' bis '0' enthalten darf.

 aus dem Zeichen '0'  Ordinalzahl 48 wird dann die Zahl 0
 aus dem Zeichen 'A' Ordinalzahl 65 wird dann die Zahl 10

 es wird also Zeichenweise das Character in einen Byte umgewandelt. Ein 'Y' darf hier nicht stehen!

 vop


----------



## deepthroat (14. September 2005)

Hi.

Es wäre mal interessant gewesen den gesamten Quelltext der Funktion zu sehen. Das Problem was ich sehe ist das abOutput auf einer 32bit Maschine in der Regel nur 4 Elemente hat da ein Pointer normalerweise eben 4 Byte groß ist. Ist denn sichergestellt, dass j nicht größer als 3 wird?


----------



## astaluego (14. September 2005)

Nein ich schätze nicht denn j wird auch in der Schleife addiert hier noch der ganze Code:


```
ByteToHalf(byte* abInput, int isize )
{
  byte abOutput[sizeof(abInput)];
  int  i,j;
  
  j = 0;
  for(i=0;i<isize;i++)
  {
    if((abInput[i] - 48) * (abInput[i] - 57) <= 0)      // 0 - 9
      abOutput[j] = abInput[i] - 48;                  
    else
      abOutput[j] = abInput[i] - 55;                    // A - F

    i++;
    abOutput[j] = abOutput[j] << 4;

    if((abInput[i] - 48) * (abInput[i] - 57) <= 0)      // 0 - 9
      abOutput[j] = abOutput[j] | (abInput[i] - 48);
    else
      abOutput[j] = abOutput[j] | (abInput[i] - 55);    // A - F
    j++;
  }

  memset(abInput, 0x00, sizeof(abInput));
  memcpy( abInput, abOutput, 8);

  return;
}
```


----------



## deepthroat (14. September 2005)

Ja, das ist definitiv falsch. Der sizeof Operator liefert nicht die Anzahl der Elemente des abInput Arrays sondern nur die Größe der Variablen, in dem Fall also die Größe eines Pointers auf byte.

Das memcpy kopiert dann immer 8 Byte von abOutput in abInput (egal wie groß abInput auch immer ist, und abgesehen davon, das abOutput nur ein Array von 4 Bytes ist).

Es kommt halt drauf an wie groß abInput ist. Evtl. ist ja sichergestellt, dass es immer 8 Byte groß ist? Dann ist es nicht ganz so falsch...

Der Code konvertiert die hexadezimalen Zeichen in abInput in entsprechende Werte und speichert jeweils einen Wert im höherwertigen, den nächsten im niederwertigen Nibble eines Bytes. 

Das 4-fache Shiften ist schon OK wie vop bereits geschrieben hat, da die Werte der Symbole (im Hexadezimalsystem) nicht größer als 15 sein können, das höherwertige Nibble also nur Nullen enthält.

Ich hab's mal ein wenig umgeschrieben (das mit der Multiplikation in der if-Anweisung ist mir eindeutig zuviel Vodoo ):
	
	
	



```
ByteToHalf(byte* abInput, int isize )
{
  byte* abOutput = calloc (isize, sizeof (byte));

  int  i;
  
  for(i=0; i < isize; i++)
  {
    int j = i / 2;
    int nibble = (i % 2 == 0) ? 4 : 0;

    if(abInput[i] >= 48 && abInput[i] <= 57)           // 0 - 9
      abOutput[j] |= ( abInput[i] - 48 ) << nibble;
    else
      abOutput[j] |= ( abInput[i] - 55 ) << nibble;    // A - F
  }

  memcpy(abInput, abOutput, isize * sizeof (byte));
  
  free (abOutput);
}
```


----------

