Page 1 of 1

Strucutre : n

Posted: Sun Apr 17, 2016 5:35 am
by nco2k
a somewhat stupid question, but what does : n mean? how do you translate it to pb? i never seen it before. :?

Code: Select all

typedef struct abc {
  ULONG def : 1;
  ULONG ghi : 21;
}
c ya,
nco2k

Re: Strucutre : n

Posted: Sun Apr 17, 2016 5:48 am
by kenmo
It's a "bit field", it means those struct members in your example take up 1 bit and 21 bits respectively, probably in one shared integer.

If you check sizeof(struct abc) I think it would give 4 bytes (it rounded up to 32 bits).

https://en.wikipedia.org/wiki/Bit_field

I don't think there's a direct way to do this in PB, you will have to do some bitshift manipulation to set/get those values.

Re: Strucutre : n

Posted: Sun Apr 17, 2016 6:14 am
by nco2k
cool thanks. :)

c ya,
nco2k

Re: Strucutre : n

Posted: Mon Apr 18, 2016 4:16 am
by idle
Quick idea to work with bit fields

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)

Re: Strucutre : n

Posted: Mon Apr 18, 2016 8:08 am
by idle
or like this maybe, so you can work with it internally or externally through the macros

for internal use

GetBitfield(Bitfield,Index)
SetBitField(BitField,index,val)

for external use, set a pointer to an external variable and use the addressed mode

SetBitFieldPointer(BitField,Address) ;reassign a bit fields pointer to an external variable
GetBitFieldAddressed(BitField,Index)
SetBitFieldAddressed(BitField,Index,value)

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) 


Re: Strucutre : n

Posted: Mon Apr 18, 2016 12:44 pm
by Lunasole
ULONG is unsigned long, Pb doesn't have unsigned long, but for bitmask it doesn't matter. The translation should be

Code: Select all

Structure abc
	def.l
	ghi.l
EndStructure
Also should notice that in purebasic long size is always 4 bytes (both on windows and linux), in C/C++ compilers it can vary from 4 to 8 bytes (comparing windows and linux), such freedom of types implementation/defines/redefines sometimes makes porting of C/C++ code to other compiler or platform very funny ^^

Re: Strucutre : n

Posted: Mon Apr 18, 2016 1:29 pm
by nco2k
wrong, the bitfield actually shares the long.

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
c ya,
nco2k

Re: Strucutre : n

Posted: Mon Apr 18, 2016 3:16 pm
by mhs
nco2k wrote:wrong, the bitfield actually shares the long.
Yes, that's right. It's the main advantage of bit fields in C.

Re: Strucutre : n

Posted: Mon Apr 18, 2016 9:22 pm
by idle
A c long is equivalent to a pb integer so for 32 bit it's 4 bytes and x64 8 bytes
when you encounter a bit field ":" in a struct the type specifies the size of a shared variable
followed by the number of bits used so the c preprocessor can do the fix ups to set and get the field vars

To access the fields you need a set of masks and offsets

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) 
or you can try one of the codes I posted which does the same, the second version you can reuse as a template
but you may need to reset the field pointer before accessing fields with
SetBitFieldPointer(BitField,Address)
then use the get macro to assign compare of do what ever you need to do
GetBitFieldAddressed(*bitfield_foo,#foo1)

Re: Strucutre : n

Posted: Tue Apr 19, 2016 7:00 am
by nco2k
a c long is always 32bit, unless visual studio just lied to me. :)

c ya,
nco2k

Re: Strucutre : n

Posted: Tue Apr 19, 2016 7:15 am
by idle
Thanks, I didn't know that, on linux it's the native size and probably the same for osx

Re: Strucutre : n

Posted: Wed Apr 20, 2016 2:05 am
by Shield
nco2k wrote:a c long is always 32bit, unless visual studio just lied to me. :)
No, the long type is at least 32 bit. What it actually is is depending on
the compiler and platform, but it definitely isn't always 32 bit.

If you want a type with a certain size in C, you have to include stdint.h and use
fixed with types such as int32_t.

Re: Strucutre : n

Posted: Wed Apr 20, 2016 7:28 am
by nco2k
yes and here its 32bit. Lunasole and idle already pointed out, that it may be different on other platforms. btw the at least statement applies for almost every type (char, short etc.), thats why fixed width integers were introduced in the first place. but you are right, i shouldnt have written always, as it could cause confusion.

c ya,
nco2k

Re: Strucutre : n

Posted: Wed Apr 20, 2016 6:19 pm
by Lunasole
nco2k wrote:wrong, the bitfield actually shares the long.

Code: Select all

//in PB (32 bits, 4 byte)
Structure Test
  bitfield.l
EndStructure
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.
What I read right now about them looks interesting way to set bits.


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

; 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 

Re: Strucutre : n

Posted: Wed Apr 20, 2016 8:56 pm
by idle
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.
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.
Though when you encounter a bit field in a structure, they're rarely used for single bits alone, which is why you need to mask them.

In the case of single bits you can also use assembly instructions BTS BTR BTC but then you can't really use them via a macro in expressions
but it's easy enough to inline them.

Also the index is from 0

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"