www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Converting C/C++ bit fields...

reply "Regan Heath" <regan netwin.co.nz> writes:
I'd like to find out what techniques people have been using to convert  
C/C++ structs containing bitfields to D, take for example this struct:

typedef struct _DCB {
     DWORD DCBlength;      /* sizeof(DCB)                     */
     DWORD BaudRate;       /* Baudrate at which running       */
     DWORD fBinary: 1;     /* Binary Mode (skip EOF check)    */
     DWORD fParity: 1;     /* Enable parity checking          */
     DWORD fOutxCtsFlow:1; /* CTS handshaking on output       */
     DWORD fOutxDsrFlow:1; /* DSR handshaking on output       */
     DWORD fDtrControl:2;  /* DTR Flow control                */
     DWORD fDsrSensitivity:1; /* DSR Sensitivity              */
     DWORD fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */
     DWORD fOutX: 1;       /* Enable output X-ON/X-OFF        */
     DWORD fInX: 1;        /* Enable input X-ON/X-OFF         */
     DWORD fErrorChar: 1;  /* Enable Err Replacement          */
     DWORD fNull: 1;       /* Enable Null stripping           */
     DWORD fRtsControl:2;  /* Rts Flow control                */
     DWORD fAbortOnError:1; /* Abort all reads and writes on Error */
     DWORD fDummy2:17;     /* Reserved                        */
     WORD wReserved;       /* Not currently used              */
     WORD XonLim;          /* Transmit X-ON threshold         */
     WORD XoffLim;         /* Transmit X-OFF threshold        */
     BYTE ByteSize;        /* Number of bits/byte, 4-8        */
     BYTE Parity;          /* 0-4=None,Odd,Even,Mark,Space    */
     BYTE StopBits;        /* 0,1,2 = 1, 1.5, 2               */
     char XonChar;         /* Tx and Rx X-ON character        */
     char XoffChar;        /* Tx and Rx X-OFF character       */
     char ErrorChar;       /* Error replacement char          */
     char EofChar;         /* End of Input character          */
     char EvtChar;         /* Received Event character        */
     WORD wReserved1;      /* Fill for now.                   */
} DCB, *LPDCB;

My initial thought was to use bit, bit[2] and bit[17] but of course D  
allocates 1 byte for each stand alone 'bit' so the structure ends up  
totally the wrong size.


Next I tried a bit[32] called _bits (this should make the struct size  
correct), and some aliases, eg.
   alias _bits[0] fBinary;

but I get the error "_bits is used as a type". That is a little odd  
considering I can write "alias EvtChar bob" (is this using EvtChar as a  
type?)


Lastly I tried to use properties, i.e.

bit fBinary()      { return _bits[0]; }
bit fBinary(bit b) { _bits[0] = b; return fBinary; }

these seem to work for the single bit ones, but the 2 bit ones:

bit[2] fDtrControl()          { return _bits[4..6]; }
bit[2] fDtrControl(bit[2] b)  { _bits[4..6] = b[]; return fDtrControl; }

that's no good, you cannot return a 'static' bit[2].

I then tried:

ubyte toUbyte(bit[] ba)      { ubyte v = 0; foreach(bit b; ba) { v *= 2; v  
+= b; } return v; }
ubyte fDtrControl()          { return toUbyte(_bits[4..6]); }
ubyte fDtrControl(ubyte b)   { _bits[4..6] = (cast(bit*)&b)[0..2]; return  
fDtrControl; }

but that gives an array bounds error in the setter. I didn't investigate  
this any further, the effort required already is quite ridiculous, such  
that I figure there must or should be a better solution.


Thoughts?

Regan
Aug 09 2005
next sibling parent reply Vathix <chris dprogramming.com> writes:
On Tue, 09 Aug 2005 07:54:16 -0400, Regan Heath <regan netwin.co.nz> wrote:

 I'd like to find out what techniques people have been using to convert  
 C/C++ structs containing bitfields to D

How about masking and shifting DWORD bits
Aug 09 2005
parent "Regan Heath" <regan netwin.co.nz> writes:
On Tue, 09 Aug 2005 08:12:17 -0400, Vathix <chris dprogramming.com> wrote:
 On Tue, 09 Aug 2005 07:54:16 -0400, Regan Heath <regan netwin.co.nz>  
 wrote:

 I'd like to find out what techniques people have been using to convert  
 C/C++ structs containing bitfields to D

How about masking and shifting DWORD bits

Sure, but I want to be able to say: DCB a; a.fParity = true; ..etc.. which I guess I can do, if I define a getter/setter for each one, and do all the bit shifting etc in them. All that effort/work.. seems like it _should_ be easier. Regan
Aug 09 2005
prev sibling parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
"Regan Heath" <regan netwin.co.nz> wrote in message 
news:opsu8ooqhn23k2f5 nrage.netwin.co.nz...
 I'd like to find out what techniques people have been using to convert 
 C/C++ structs containing bitfields to D, take for example this struct:

 Thoughts?

import std.intrinsic; // a bit field template BitField(uint n, alias data) { int get(){ return bt(&data,n); } void set(int m){m?bts(&data,n):btr(&data,n);} } // a two-bit field template BitField2(uint n, alias data) { int get(){ return data >> n & 3; } void set(int m){ data = (data & ~(3<<n)) | (m<<n) ;} } struct Foo { uint fields; mixin BitField!(0,fields) f1; mixin BitField!(1,fields) f2; mixin BitField2!(2,fields) f3; mixin BitField!(4,fields) f4; } int main() { Foo x; x.f1.set = true; x.f3.set = 3; x.f4.set = true; printf("fields: %d\n",x.fields); printf("x.f1 %d\n", x.f1.get); printf("x.f2 %d\n", x.f2.get); printf("x.f3 %d\n", x.f3.get); printf("x.f4 %d\n", x.f4.get); return 0; }
Aug 09 2005
next sibling parent reply Burton Radons <burton-radons smocky.com> writes:
Ben Hinkle wrote:

 "Regan Heath" <regan netwin.co.nz> wrote in message 
 news:opsu8ooqhn23k2f5 nrage.netwin.co.nz...
 
I'd like to find out what techniques people have been using to convert 
C/C++ structs containing bitfields to D, take for example this struct:

[snip]
Thoughts?

import std.intrinsic; // a bit field template BitField(uint n, alias data) { int get(){ return bt(&data,n); } void set(int m){m?bts(&data,n):btr(&data,n);} } // a two-bit field template BitField2(uint n, alias data) { int get(){ return data >> n & 3; } void set(int m){ data = (data & ~(3<<n)) | (m<<n) ;} } struct Foo { uint fields; mixin BitField!(0,fields) f1; mixin BitField!(1,fields) f2; mixin BitField2!(2,fields) f3; mixin BitField!(4,fields) f4; } int main() { Foo x; x.f1.set = true; x.f3.set = 3; x.f4.set = true; printf("fields: %d\n",x.fields); printf("x.f1 %d\n", x.f1.get); printf("x.f2 %d\n", x.f2.get); printf("x.f3 %d\n", x.f3.get); printf("x.f4 %d\n", x.f4.get); return 0; }

Clever boy. I'll need to remember that. I'd use the more general: template BitField (uint start, uint count, alias data, type = uint) { static assert ((1L << (start + count)) - 1 <= data.max); const uint mask = (1 << count) - 1; type get () { return cast (type) ((data >> start) & mask); } type set (type value) { data = (data & ~(mask << start)) | ((cast (typeof (data)) value & mask) << start); return value; } } Too bad opCall doesn't work with mixins.
Aug 09 2005
parent Burton Radons <burton-radons smocky.com> writes:
Burton Radons wrote:

         const uint mask = (1 << count) - 1;

That should be "const typeof (data) mask = (1UL << count) - 1;" so that it works with long.
Aug 09 2005
prev sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
Nice! Thanks.

Still, it would be nice if D had a better way to handle bitfields, if only  
to ease conversion of C/C++ structs containing them. The fact that we're  
not using the built in bit support suggests to me that it's not as useful  
as it should be.

Regan

On Tue, 9 Aug 2005 10:25:44 -0400, Ben Hinkle <bhinkle mathworks.com>  
wrote:
 "Regan Heath" <regan netwin.co.nz> wrote in message
 news:opsu8ooqhn23k2f5 nrage.netwin.co.nz...
 I'd like to find out what techniques people have been using to convert
 C/C++ structs containing bitfields to D, take for example this struct:

 Thoughts?

import std.intrinsic; // a bit field template BitField(uint n, alias data) { int get(){ return bt(&data,n); } void set(int m){m?bts(&data,n):btr(&data,n);} } // a two-bit field template BitField2(uint n, alias data) { int get(){ return data >> n & 3; } void set(int m){ data = (data & ~(3<<n)) | (m<<n) ;} } struct Foo { uint fields; mixin BitField!(0,fields) f1; mixin BitField!(1,fields) f2; mixin BitField2!(2,fields) f3; mixin BitField!(4,fields) f4; } int main() { Foo x; x.f1.set = true; x.f3.set = 3; x.f4.set = true; printf("fields: %d\n",x.fields); printf("x.f1 %d\n", x.f1.get); printf("x.f2 %d\n", x.f2.get); printf("x.f3 %d\n", x.f3.get); printf("x.f4 %d\n", x.f4.get); return 0; }

Aug 09 2005
parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
 Still, it would be nice if D had a better way to handle bitfields, if only 
 to ease conversion of C/C++ structs containing them. The fact that we're 
 not using the built in bit support suggests to me that it's not as useful 
 as it should be.

I haven't read the docs in detail but probably bit arrays have too much freedom in how they are implemented to be reliable for replacing C bit fields. ie- the packing and alignment become crucial and that's something that the shifting implementation can control (since they have to control it). To me the only problem with bitfields is that the auto .h->.d translator (I can't remember the name of the program) seems to ignore them so any struct with a bitfield gets hosed (without warning, I believe).
Aug 09 2005
parent "Regan Heath" <regan netwin.co.nz> writes:
On Tue, 9 Aug 2005 19:07:53 -0400, Ben Hinkle <ben.hinkle gmail.com> wrote:
 Still, it would be nice if D had a better way to handle bitfields, if  
 only
 to ease conversion of C/C++ structs containing them. The fact that we're
 not using the built in bit support suggests to me that it's not as  
 useful
 as it should be.

I haven't read the docs in detail but probably bit arrays have too much freedom in how they are implemented to be reliable for replacing C bit fields. ie- the packing and alignment become crucial and that's something that the shifting implementation can control (since they have to control it). To me the only problem with bitfields is that the auto .h->.d translator (I can't remember the name of the program) seems to ignore them so any struct with a bitfield gets hosed (without warning, I believe).

I think the problem with .h->.d translations is that there is no simple, easy way to translate bitfields. Why can't I use: bit[32] data; alias data[0] a; alias data[1] b; alias data[2] c; ..etc..? Regan
Aug 09 2005