PDA

View Full Version : How to manipulate specific bits of a variable



SilverWarior
12-07-2013, 05:09 PM
Hi guys!

How can I read and manupilate seperate bits of a varable?
For instance if I have 8 bit Integer variable and want to read state of 3rd bit or change its state to 1 or 0 how do I do this?

In C++ I could declare Array of Boolean with the size of the number bits used for my integer value. Then I would use pointer to assign same memory block that my integer variable uses to my array variable. This would alow me of accesing seperate bits like accesing seperate items in array.

I would like to do smething similar in Object Pascal preferable without the use of pointers.

Dan
12-07-2013, 05:33 PM
function GetBit(const Value, Bit: LongWord): Boolean;
begin
Result := Boolean((Value shr Bit) and 1);
end;

function SetBit(const Value, Bit: LongWord; const NewBitValue: Boolean): LongWord;
beign
Result := (Value and not LongWord(1 shl Bit)) or (LongWord(NewBitValue) shl Bit)
end;


there may be some errors in the code but generally it should work. Value is the 32 bit combination that you are working with, Bit is the order of the bit that you want to read/change.
However, in pascal there is a more convenient way of working with bit flags - sets. they are very neatly designed, support up to 128 bits and compile into the same optimized binary math.

User137
13-07-2013, 11:53 PM
You just have to know that sets have different size, depending on compiler settings. In Delphi the size scales dynamically based on its range, starting from 1 byte. In Lazarus the default smallest size for set is 4 bytes. Compiler options can change that behavior.

paul_nicholls
14-07-2013, 06:01 AM
Using freepascal, you can now have bit packed records like so:



{
Flag register:
---------------
Bit[0] - Reserved
Bit[1] - c (Unsigned Carry and Unsigned Borrow flag)
Bit[2] - z (Zero flag)
Bit[3] - Reserved
Bit[4] - Reserved
Bit[5] - Reserved
Bit[6] - o (Signed Overflow Flag)
Bit[7] - n (Negative Flag; aka Sign Flag)
}


type
TBit = 0..1;
TFlags = bitpacked record
_0 : TBit;
c : TBit;
z : TBit;
_3 : TBit;
_4 : TBit;
_5 : TBit;
o : TBit;
n : TBit;
end;

here, you can access all the separate bits as a separate variable in the record...rather neat! :)
It isn't supported under Delphi unfortunately, but if you only use freepascal, then great ;)

pitfiend
14-07-2013, 08:46 AM
if you want to stay delphi compatible, you can use and/or operators to do some bit operations. for example, $08 is equivalent to 0000 1000, then you can test ( somevar and $08 ) = $08 to check if 4th bit is set, if you want to check 7th bit you use $40, ( somevar and $40 ) = $40. there's a trick that worked for me, as you know, every bit is a power of 2, the first 8 bits are 1, 2, 4, 8, 16, 32, 64, 128, if you wrote them in hex, you get $01, $02, $04, $08, $10, $20, $40, $80, can you see the pattern? it stays the same if you work with more bits, just add a 0 at the end and you get 4 more bits or a nibble (half byte).

Carver413
14-07-2013, 02:21 PM
Using freepascal, you can now have bit packed records like so:



{
Flag register:
---------------
Bit[0] - Reserved
Bit[1] - c (Unsigned Carry and Unsigned Borrow flag)
Bit[2] - z (Zero flag)
Bit[3] - Reserved
Bit[4] - Reserved
Bit[5] - Reserved
Bit[6] - o (Signed Overflow Flag)
Bit[7] - n (Negative Flag; aka Sign Flag)
}


type
TBit = 0..1;
TFlags = bitpacked record
_0 : TBit;
c : TBit;
z : TBit;
_3 : TBit;
_4 : TBit;
_5 : TBit;
o : TBit;
n : TBit;
end;

here, you can access all the separate bits as a separate variable in the record...rather neat! :)
It isn't supported under Delphi unfortunately, but if you only use freepascal, then great ;)
thats great Paul, I'll have to give that a try

Darkhog
14-07-2013, 03:14 PM
Using freepascal, you can now have bit packed records like so:



{
Flag register:
---------------
Bit[0] - Reserved
Bit[1] - c (Unsigned Carry and Unsigned Borrow flag)
Bit[2] - z (Zero flag)
Bit[3] - Reserved
Bit[4] - Reserved
Bit[5] - Reserved
Bit[6] - o (Signed Overflow Flag)
Bit[7] - n (Negative Flag; aka Sign Flag)
}


type
TBit = 0..1;
TFlags = bitpacked record
_0 : TBit;
c : TBit;
z : TBit;
_3 : TBit;
_4 : TBit;
_5 : TBit;
o : TBit;
n : TBit;
end;

here, you can access all the separate bits as a separate variable in the record...rather neat! :)
It isn't supported under Delphi unfortunately, but if you only use freepascal, then great ;)

Does variable names here actually bears any importance or could I just write:

type
TBit = 0..1;
TByte = bitpacked record //TByte to avoid confusion with actual Byte type
b1 : TBit;
b2 : TBit;
b3 : TBit;
b4 : TBit;
b5 : TBit;
b6 : TBit;
b7 : TBit;
b8 : TBit;
end;

//edit: I wrote (but didn't test) function that would check if specific bit is set. You'll need math unit for that one:

function IsBitSet(num:integer;bit:byte):Boolean
var bitnum:Integer;
begin
bitnum:= Trunc(intpower(2,bit);
Result:= (num and bitnum) = bitnum;
end;
Though it should work fine.

User137
14-07-2013, 06:51 PM
//edit: I wrote (but didn't test) function that would check if specific bit is set. You'll need math unit for that one:

function IsBitSet(num:integer;bit:byte):Boolean
var bitnum:Integer;
begin
bitnum:= Trunc(intpower(2,bit);
Result:= (num and bitnum) = bitnum;
end;
Though it should work fine.
Dan already gave more optimized code for that

function GetBit(const Value, Bit: LongWord): Boolean;
begin
Result := Boolean((Value shr Bit) and 1);
end;
Both trunc() and intpower() do a massive amount of extra work.

Darkhog
14-07-2013, 08:03 PM
I guess it should work fine too. But why using longword for bit no.? Byte would do here much better and I don't suppose we'll need to check like 5000th bit of value soon. Therefore longword would just waste memory while byte would be much more memory-efficient here, especially when dealing with embedded systems.

imcold
14-07-2013, 08:52 PM
Byte would be worse actually - more generated code. And you wouldn't save any memory, as it would be most likely passed in a register or pushed as a 4B value on the stack, depending on ABI.