
Code: Select all
typedef struct abc {
ULONG def : 1;
ULONG ghi : 21;
}
nco2k
Code: Select all
typedef struct abc {
ULONG def : 1;
ULONG ghi : 21;
}
Code: Select all
Define.i BF_Index,BF_Offset,BF_Mask
Macro NewBitField(BitField,NumFields)
BF_Index = 0
BF_Offset = 0
Global Dim BF_#BitField.i(1,NumFields)
EndMacro
Macro BF_32(BitField,NumBits)
BF_Mask = $FFFFFFFF
BF_Mask >> (32-NumBits)
BF_#BitField(0,BF_Index) = (BF_Mask << BF_Offset)
BF_#BitField(1,BF_Index) = BF_Offset
BF_Offset+NumBits
BF_Index+1
EndMacro
Macro BF_Get(Var,BitField,Index)
((var & BF_#BitField(0,index)) >> BF_#BitField(1,index))
EndMacro
Macro BF_Set(Var,BitField,index,val)
var | (val << BF_#BitField(1,index))
EndMacro
Enumeration ;indexes to bitfield entries
#Foo1
#Foo21
#Foo9
EndEnumeration
NewBitField(foo,3) ;Define a Bit Field
BF_32(foo,1) ;Define the field width
BF_32(foo,21)
BF_32(foo,9)
Global b.l
BF_Set(b,foo,#Foo1,1) ;set the var at the Bit Field define with the value
BF_Set(b,foo,#Foo21,2097151)
BF_Set(b,foo,#Foo9,511)
Debug BF_Get(b,foo,#Foo1) ;get the value by the Bit Field define
Debug BF_Get(b,foo,#Foo21)
Debug BF_Get(b,foo,#Foo9)
Code: Select all
Structure BitField
*bits.Integer
Size.l
Addressed.l
BF_Index.l
BF_Offset.l
BF_Mask.i
Array BF.i(1,0)
EndStructure
Procedure NewBitField(NumFields,Address=0,size=4)
Protected *this.BitField
*this = AllocateStructure(BitField)
If *this
*this\size = size
If Address
*this\bits = Address
*this\Addressed = 1
EndIf
ReDim *this\bf(1,NumFields)
ProcedureReturn *this
EndIf
EndProcedure
Procedure FreeBitField(*BitField)
FreeStructure(*BitField)
EndProcedure
Procedure AddBitField(*BitField.BitField,NumBits)
Select *BitField\size
Case 4
*BitField\BF_Mask = $FFFFFFFF
*BitField\BF_Mask >> (32-NumBits)
Case 8
*BitField\BF_Mask = $FFFFFFFFFFFFFFFF
*BitField\BF_Mask >> (64-NumBits)
EndSelect
*BitField\bf(0,*BitField\BF_Index) = (*BitField\BF_Mask << *BitField\BF_Offset)
*BitField\bF(1,*BitField\BF_Index) = *BitField\BF_Offset
*BitField\BF_Offset + NumBits
*BitField\BF_Index+1
EndProcedure
Macro GetBitfield(Bitfield,Index)
((BitField\bits & BitField\bf(0,index)) >> BitField\bf(1,index))
EndMacro
Macro GetBitFieldAddressed(BitField,Index)
((BitField\bits\i & BitField\bf(0,index)) >> BitField\bf(1,index))
EndMacro
Macro SetBitFieldAddressed(BitField,index,val)
BitField\bits\i | (val << BitField\bf(1,index))
EndMacro
Macro SetBitField(BitField,index,val)
BitField\bits | (val << BitField\bf(1,index))
EndMacro
Macro SetBitFieldPointer(BitField,Address)
BitField\bits = Address
EndMacro
;example
Enumeration ;set up indexes to bitfield entries identifying their size
#Foo1
#Foo21
#Foo9
EndEnumeration
Global *foo.BitField ,*bar.BitField
*foo = NewBitField(3) ;Define a Bitfield
AddBitField(*foo,1) ;set up field widths for foo
AddBitField(*foo,21)
AddBitField(*foo,9)
SetBitField(*foo,#Foo1,1) ;set the var by it's bit field def at index with the value
SetBitField(*foo,#Foo21,2097151)
SetBitField(*foo,#Foo9,511)
Debug GetBitfield(*foo,#Foo1) ;get the value by field defention at index
Debug GetBitfield(*foo,#Foo21)
Debug GetBitfield(*foo,#Foo9)
*bar = NewBitField(3,@*Foo\bits) ;define a new bit field bit but set to an external var
AddBitField(*bar,1) ;set up the field widths
AddBitField(*bar,21)
AddBitField(*bar,9)
Debug GetBitFieldAddressed(*bar,#foo1)
Debug GetBitFieldAddressed(*bar,#foo21)
Debug GetBitFieldAddressed(*bar,#foo9)
Global bits.l
SetBitFieldPointer(*bar,@bits) ;reasign bars pointer to bits
SetBitFieldAddressed(*bar,#foo1,1) ;sets bits values via bar
SetBitFieldAddressed(*bar,#foo21,1024)
SetBitFieldAddressed(*bar,#foo9,256)
Debug GetBitFieldAddressed(*bar,#foo1)
Debug GetBitFieldAddressed(*bar,#foo21)
Debug GetBitFieldAddressed(*bar,#foo9)
FreeBitField(*foo)
FreeBitField(*bar)
Code: Select all
Structure abc
def.l
ghi.l
EndStructure
Code: Select all
//in C (32 bits, 4 byte)
struct Test {
long var1 : 8;
long var2 : 1;
long var3 : 23;
};
//in PB (32 bits, 4 byte)
Structure Test
bitfield.l
EndStructure
Yes, that's right. It's the main advantage of bit fields in C.nco2k wrote:wrong, the bitfield actually shares the long.
Code: Select all
#mask_var1 = %00000000000000000000000011111111 ;; 8
#mask_var2 =%00000000000000000000000100000000 ;: 1
#mask_var3 =%11111111111111111111111000000000 ;: 23
#ofs_var1=0
#ofs_var2 = 8
#ofs_var3 = 9
;to get a field value
x = ((var & mask) >> ofs)
;to set a field
var | (val << ofs)
No, the long type is at least 32 bit. What it actually is is depending onnco2k wrote:a c long is always 32bit, unless visual studio just lied to me.![]()
Yes I missed, never encountered with those bitfields before and didn't even know about them (just assumed, as it often with me in such cases ^^) until you told I'm wrong.nco2k wrote:wrong, the bitfield actually shares the long.
Code: Select all
//in PB (32 bits, 4 byte) Structure Test bitfield.l EndStructure
Code: Select all
; check if specified value has specified bit set up
; "Value" is bitmask, "Bit" is int representing bit # (starting from 1, up to 32 or more)
; RETURN: 1 or 0
Macro BitGet (Value, Bit)
Bool(Value & (1 << (Bit - 1))) ; also: ((Value & (1 << (Bit - 1))) >> (Bit - 1)), ~~(Value & (1 << (Bit - 1))) ; (both won't work nice)
EndMacro
; set up specified bit
; "Value" is bitmask, "Bit" is int representing bit # (starting from 1, up to 32 or more)
; RETURN: modified bitmask (or result stored inside Value, if no assigment)
Macro BitSet (Value, Bit)
Value | (1 << (Bit - 1)) ; this macro IS NOT SAFE in expressions where it surrounded by "~,<<,>>,%,!" operators. Add brackets to this string for this (that will also disallow use w/o assigment).
EndMacro
; removes specified bit
; "Value" is bitmask, "Bit" is int representing bit # (starting from 1, up to 32 or more)
; RETURN: modified bitmask (or result stored inside Value, if no assigment)
Macro BitOff (Value, Bit)
Value ! (1 << (Bit - 1)) ; this macro IS NOT SAFE in expressions where it surrounded by "~,<<,>>,%" operators. Add brackets to this string for this (that will also disallow use w/o assigment).
EndMacro
;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;
Structure Test
bitfield.l
EndStructure
Define T.Test
BitSet(T\bitfield, 2) ; now bit #2 is set (or bit 1, if start counting from 0)
T\bitfield = BitSet(T\bitfield, 22) ; the same for bit 22 (21)
Debug T\bitfield
T\bitfield = BitOff(T\bitfield, 2)
BitOff(T\bitfield, 22) ; same for bit 22 (21)
Debug T\bitfield ; 0
When it comes to single bits the overhead of setting up a mask and offsets might seem excessive but then that's what the compiler should do.Lunasole wrote: But can't say it is better than "classical" path like following example, C declaration when every bit has its own variable seems excessive enough and might be confusing when reading code using it.
Code: Select all
Macro BitSet(var, bit)
var | (1 << bit)
EndMacro
Macro BitClear(var,bit)
var & ~(1 << bit)
EndMacro
Macro BitCompliment(var, bit)
var ! (1 << bit)
EndMacro
Macro BitGet(var, bit)
(var >> bit) & 1
EndMacro
BitField.l
BitSet(BitField,1)
BitSet(BitField,30)
Debug RSet(Bin(BitField,#PB_Long),32,"0") + " set 1 and 30"
BitClear(BitField,1)
Debug RSet(Bin(BitField,#PB_Long),32,"0") + " cleared 1"
BiTCompliment(BitField,1)
BitCompliment(BitField,30)
Debug RSet(Bin(BitField,#PB_Long),32,"0") + " toggled 1 and 30, 1 on 30 off"
Debug Str(Bitget(BitField,1)) + " on" ;> 0 true
!BTS [v_BitField],30 ;Bit Test Set
Debug Str(Bitget(BitField,30)) + " on";> 0 true
!BTR [v_BitField],1 ;Bit Test Reset
Debug Str(Bitget(BitField,1)) + " off"; off
!BTC [v_BitField],1 ;Bit Test Compliment
Debug Str(Bitget(BitField,1)) + " on"