Results 1 to 10 of 10

Thread: How to manipulate specific bits of a variable

  1. #1

    Question How to manipulate specific bits of a variable

    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.

  2. #2
    Code:
    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.
    Last edited by Dan; 12-07-2013 at 05:39 PM.

  3. #3
    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.

  4. #4
    Using freepascal, you can now have bit packed records like so:

    Code:
    {
        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

  5. #5
    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).
    Last edited by pitfiend; 14-07-2013 at 08:49 AM.

  6. #6
    PGDCE Developer Carver413's Avatar
    Join Date
    Jun 2010
    Location
    Spokane,WA,Usa
    Posts
    206
    Quote Originally Posted by paul_nicholls View Post
    Using freepascal, you can now have bit packed records like so:

    Code:
    {
        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

  7. #7
    Quote Originally Posted by paul_nicholls View Post
    Using freepascal, you can now have bit packed records like so:

    Code:
    {
        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:
    Code:
    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:
    Code:
    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.
    Last edited by Darkhog; 14-07-2013 at 03:23 PM.

  8. #8
    Quote Originally Posted by Darkhog View Post
    //edit: I wrote (but didn't test) function that would check if specific bit is set. You'll need math unit for that one:
    Code:
    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
    Code:
    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.

  9. #9
    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.

  10. #10
    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.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •