Thread overview
Converting C/C++ bit fields...
Aug 09, 2005
Regan Heath
Aug 09, 2005
Vathix
Aug 09, 2005
Regan Heath
Aug 09, 2005
Ben Hinkle
Aug 09, 2005
Burton Radons
Aug 09, 2005
Burton Radons
Aug 09, 2005
Regan Heath
Aug 09, 2005
Ben Hinkle
Aug 09, 2005
Regan Heath
August 09, 2005
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
August 09, 2005
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
August 09, 2005
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
August 09, 2005
"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;
}


August 09, 2005
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.
August 09, 2005
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.
August 09, 2005
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:
> [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;
> }
>
>

August 09, 2005
> 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).


August 09, 2005
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