Frage

I have to store up to 7 bytes of data in a single variable, and be able to read and write the individual bits. With 4 bytes this is a piece of cake, I just use a for loop and perform a bit shift to either write the bit or read it:

data : int64;

data := $01 + ($00 shl 8 ) + ($00 shl 16 ) + ($FF shl 24);

for i := 31 downto 0 do
     begin
          if ((data shr i) and 1) = 1 then ShowMessage('data bit was one')
          else ShowMessage('data Bit was Zero');

end;

This reads the bits out in the correct order.

However, when I try and use this method for more than 32 bits is seems to fall down:

data : int64;

data := $01 + ($00 shl 8 ) + ($00 shl 16 ) + ($00 shl 24) + ($FF shl 32);

for i := 39 downto 0 do
     begin
          if ((data shr i) and 1) = 1 then ShowMessage('data bit was one')
          else ShowMessage('data Bit was Zero');

end;

This does not output the bits in the correct order, the $FF seems to get pushed to the back of the stack. It seems to read bits 31 to 0 then bits 39 to 32. How do I overcome this?

War es hilfreich?

Lösung

Your constants are treated as Int32 values, and calculations work with 32-bit values, and casting to Int64 occurs after all calculations. SHL executes as
{Value shl (Shift mod DATASIZE)}, where DATASIZE is 32, so {shl 32} is equivalent to {shl 0} for 32-bit type. Compare

  i64 := Int64($FF) shl 32;
and
  i64 := $FF shl 32;

(for 32-bit compiler, at least)

Just cast constant(s) to Int64 to help the compiler a bit.

Andere Tipps

Do you really use the Int64 representation? Otherwise, if you are only out for the bits, you can simply declare a proper type and use the usual set syntax. You can also use Include/Exclude to set/reset single bits.

type
  T64BitSet = set of 0..63;

var
  data: T64BitSet;

begin
  data := [0, 32..39];  // set Bits

  for i := 39 downto 0 do
    begin
      if i in data then
        <data bit was one>
      else
        <data Bit was Zero>;
  end;
end;

The documentation for the bitwise shift operators says (with my emphasis):

The operations x shl y and x shr y shift the value of x to the left or right by y bits, which (if x is an unsigned integer) is equivalent to multiplying or dividing x by 2^y; the result is of the same type as x. For example, if N stores the value 01101 (decimal 13), then N shl 1 returns 11010 (decimal 26). Note that the value of y is interpreted modulo the size of the type of x. Thus for example, if x is an integer, x shl 40 is interpreted as x shl 8 because an integer is 32 bits and 40 mod 32 is 8.

This explains the treatment of:

$FF shl 32

The literal $FF is a 32 bit integer and this expression is the same as: $FF shl 0 which is $FF.

You need the left hand operand to be a 64 bit type which is achieved by way of a cast:

UInt64($FF) shl 32
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top