Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Wie function getbits(x:byte): TBitarray realisieren ?


catweasel - Mo 09.02.04 20:36
Titel: Wie function getbits(x:byte): TBitarray realisieren ?
Hi,

ich steh gerade ein bischen auf dem Schlauch. Hab mich mit Bitmanipulation noch nicht so bechäftigt..
Meine Frage ist: Wie kann ich die Bits eines Bytes auslesen...

Ich möchte im Prinzip etwas haben wie:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
var
bitarray : array[1..8of boolean;
x : byte;

function getbits(x:byte): array of boolean:
var z : integer;
begin
for z:= low(bitarray) to high(bitarray) do
  Result[z] := 
// Naja hier müsste ich irgendwie an die Bits des übergebenen X
// rankommen ....
end;


Ich denke was das werden soll ist klar:
Je nachdem ob das Bit eine 1 oder 0 ist soll das array true oder false enthalten.... Wie mache ich das .. ?

Catweasel


Motzi - Mo 09.02.04 21:07

Ungetestet, aber müsste funktionieren...

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
type
  TBitArray = array[0..7of Boolean;

function getbits(x: Byte): TBitArray:
var
  i: Integer;
begin
  for i := Low(Result) to High(Result) do
    Result[i] := Boolean(x and (1 shl i));
end;


catweasel - Mo 09.02.04 21:13

Zitat:
Boolean(x and (1 shl i));


hm... ich kann irgendwie mit der Funtion boolean() nix anfangen.. Gibts die überhaupt (ich kann die nirgends finden ...) ?

Catweasel...


Anonymous - Mo 09.02.04 21:23

Das ist keine Fkt, sondern ein Typecast von irgendeinem integer nach boolean


catweasel - Mo 09.02.04 21:32

öhmmm :oops: achso ... :)


Motzi - Mo 09.02.04 21:36

obbschtkuche hat folgendes geschrieben:
Das ist keine Fkt, sondern ein Typecast von irgendeinem integer nach boolean

Ganz genau..!


Delphi-Quelltext
1:
1 shl i                    

die Zahl Eins wird um i Stellen nach links geshiftet


Delphi-Quelltext
1:
and (1 shl i)                    

x wird mit dem Ergebnis der Shift-Operation and-verknüpft. Ist das Bit gesetzt, dann ist das Ergebnis ein Vielfaches von 2, andernfalls 0


Delphi-Quelltext
1:
Boolean(x and (1 shl i))                    

Dieser Typecast wandelt das Ergebnis in einen Boolean (True/False) um. Dabei gilt 0=False und als umkehrschluss - alles was ungleich null ist ist dann True..!


catweasel - Mo 09.02.04 23:34

Ah Danke ..!


catweasel - Di 10.02.04 00:34

Zitat:
Boolean(x and (1 shl i))


Das das da oben ein Cast ist hab ich nu kapiert... :)

Aber eine Frage noch... : :?:

ich hab noch ein bischen an den Operatoren shl bzw. shr zu kabbern und muss mir das mit den logischen Operatoren nochmal genauer anguggen..
Z.B. Warum gerade die Zahl 1 verschieben.. :?:

@motzi (oder sonst jemand :-) )

Könntest du mir zu lernzwecken auch die Umkehrfunktion kurz erläutern?
Also


Delphi-Quelltext
1:
function getbyte(bitarray:TBitarray):byte;                    


Wäre super.. :-)

Catweasel


Sven - Di 10.02.04 08:10

Nur mal am Rande, in der Unit Classes ist ein Typ deklariert der da heißt TBits. Vielleicht leistet dieser bessere Dienste.


Motzi - Di 10.02.04 14:29

Also shl / shr sind im Prinzip ganz einfach.. sie verschieben die Bits einfach um x Bit nach rechts oder links und füllen die dabei entstehenden Leerräume einfach mit Nullen.

Quelltext
1:
2:
3:
00000001 shl 1
--------------
00000010



Quelltext
1:
2:
3:
00000001 shl 5
--------------
00100000


Ich verschiebe in dem Code die Zahl 1 weil sie in der Binär-Darstellung nur eine 1 hat und die an erster Stelle ist. Ich shifte dann einfach immer um i Stellen wodurch ich dann immer das nächste Bit gesetzt habe:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
00000001 shl 0 = 00000001
00000001 shl 1 = 00000010
00000001 shl 2 = 00000100
00000001 shl 3 = 00001000
00000001 shl 4 = 00010000
00000001 shl 5 = 00100000
00000001 shl 6 = 01000000
00000001 shl 7 = 10000000

Das wird dann per and verknüpft und das Ergebnis in einen Boolean umgewandelt.

Die Umkerfunktion könnte also ungefähr so ausschauen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
function GetByte(const aBitArray: TBitArray): Byte;
var
  i: Integer;
begin
  Result := 0;
  for i := Low(aBitArray) to High(aBitArray) do
    if aBitArray[i] then
      Result := Result or (1 shl i);
end;


AndyB - Di 10.02.04 15:55

Motzi hat folgendes geschrieben:

Delphi-Quelltext
1:
Boolean(x and (1 shl i))                    

Dieser Typecast wandelt das Ergebnis in einen Boolean (True/False) um. Dabei gilt 0=False und als umkehrschluss - alles was ungleich null ist ist dann True..!

Gut beobachtet. Und wenn jetzt jemand kommt, und mit
if BitArray[x] = True then testet, wird er bis auf BitArray[0] immer False bekommen, weil True für Boolean als True = 1 deklariert ist. Da ab (einschließlich) Byte(BitArray[1]) > 1 ist, ergibt eben "x = 1 mit x>1" immer False.

Aus diesem Grund beforzuge ich erstens

Delphi-Quelltext
1:
if BitArray[x] then                    

und zeitens unterlasse ich Typecasts zu Boolean, wenn das nicht unbedingt nötig ist, indem ich auf ungleich Null prüfe.

Delphi-Quelltext
1:
Result[i] := x and (1 shl i) <> 0;                    

Dadurch übernimmt der Compiler die nötige Umwandlung und macht aus allen Werten ungliech 0 die 1.


Motzi - Di 10.02.04 18:41

AndyB hat folgendes geschrieben:
Aus diesem Grund beforzuge ich erstens

Delphi-Quelltext
1:
if BitArray[x] then                    

Tu ich auch (wie man oben sieht)...

Zitat:
und zeitens unterlasse ich Typecasts zu Boolean, wenn das nicht unbedingt nötig ist, indem ich auf ungleich Null prüfe.

Delphi-Quelltext
1:
Result[i] := x and (1 shl i) <> 0;                    

Dadurch übernimmt der Compiler die nötige Umwandlung und macht aus allen Werten ungliech 0 die 1.

Stimmt.. das hab ich nicht beachtet.. dachte bis jetzt es wird jeder Wert <> 0 als True angesehen, dies trifft aber nur bei einer Prüfung ala

Delphi-Quelltext
1:
if Ausdruck then                    

zu und nicht bei

Delphi-Quelltext
1:
if Ausdruck = True then                    

da ja ein Boolean im Prinzip eine Menge mit 2 Werten darstellt und Ord(True) = 1 ist...


catweasel - Di 10.02.04 23:30

Zitat:
Nur mal am Rande, in der Unit Classes ist ein Typ deklariert der da heißt TBits. Vielleicht leistet dieser bessere Dienste.

Naja soo aufregend is der TBits typ ja auch nich... Is ja auch nur ein array of boolean.. gut ok.. es dimensioniert sich selbst.. aber wann hat ein byte schonmal weniger oder mehr als 8 bits ...?
Ich geb zu: für words und doubblewords isses ganz brauchbar, aber für byte reicht auch das eigene Array....
Oder kann TBits noch was geniales das ich übersehen hab ?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
function GetByte(const aBitArray: TBitArray): Byte; 
var 
  i: Integer; 
begin 
  Result := 0
  for i := Low(aBitArray) to High(aBitArray) do 
    if aBitArray[i] then 
      Result := Result or (1 shl i); 
end;


Da muss ich da auch analog zur getbits funktion auf <> 0 testen, oder?!

Zitat:
Gut beobachtet. Und wenn jetzt jemand kommt, und mit
if BitArray[x] = True then
testet,


Genau das hab ich nämlich beobachtet .. Bit 1 war immer abwechseln false oder true und der rest immr false...

Zitat:
Dadurch übernimmt der Compiler die nötige Umwandlung und macht aus allen Werten ungliech 0 die 1

Genau da liegt irgendwie das Problem. Man denkt ein bool wert is true wenn er wahr is und dann ist er auf einmal war wenn er falsch wahr ist .. :shock: Ist das jetzt doppelte Verneinung oder was ? :roll:

Wo liegt genau der Unterschied zwischen:

if Ausdruck then und  if Ausdruck = True then

Und vor allem: Was macht der Compiler da einfach so.. Und warum geht der type cast in diesem Fall schief ?

Catweasel


AndyB - Mi 11.02.04 10:03

catweasel hat folgendes geschrieben:
Da muss ich da auch analog zur getbits funktion auf <> 0 testen, oder?!

Nein, denn hier interessiert dich ja, welches Bit gesetzt ist.


Zitat:
Und warum geht der type cast in diesem Fall schief ?

Der Typecast geht hier nicht schief, aber er liefert ein Ergebnis, das man nicht gleich ("=") einem Wert setzen darf.
Ein Beispiel:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
True = 0000 0001
False = 0000 0000

Result := Boolean(1 shl 3)    = 0000 1000
if Result = True then      =  if 0000 1000 = 0000 0001 then  FEHLER

// für das Erste Bit kommt hier fogendes heraus:
Result := Boolean(1 shl 0)    = 0000 0001
if Result = True then      =  if 0000 0001 = 0000 0001 then   OK

// Mit <> 0 testen:
Result := 1 shl 3 <> 0    = 0000 0001
if Result = True then      =  if 0000 0001 = 0000 0001 then   OK


Zitat:
Was macht der Compiler da einfach so.

Er macht aus

Delphi-Quelltext
1:
Result := 1 shl 3 <> 0;                    

grob diesen Code:

Delphi-Quelltext
1:
if 1 shl 3 <> 0 then Result := True else Result := False;                    

Da der Compiler Assembler-Code produziert, kann er das noch ganz schön optimieren, womit es nicht spührbar langsamer als der direkte Typecast läuft.

Zitat:
Wo liegt genau der Unterschied zwischen:
if Ausdruck then und  if Ausdruck = True

Bei erstem prüft der Compiler auf "<> 0". Bei zweiten wird direkt mit "= 1" geprüft.