www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - C struct (with bitfields) to D and back

reply Serg Kovrov <kovrov no.spam> writes:
Hi all, I have a problem translating certain C structure to D. Here it is:

 typedef struct tag_SCRIPT_CONTROL { 
   DWORD uDefaultLanguage :16; 
   DWORD fContextDigits :1; 
   DWORD fInvertPreBoundDir :1; 
   DWORD fInvertPostBoundDir :1; 
   DWORD fLinkStringBefore :1; 
   DWORD fLinkStringAfter :1; 
   DWORD fNeutralOverride :1; 
   DWORD fNumericOverride :1; 
   DWORD fLegacyBidiClass :1; 
   DWORD fReserved :8; 
 } SCRIPT_CONTROL;

It some sort of telling C compiler size of a struct member. I never used such technique before. htod output following:
 struct tag_SCRIPT_CONTROL
 {
     DWORD __bitfield1;
     DWORD uDefaultLanguage() { return (__bitfield1 >> 0) & 0xffff; }
     DWORD uDefaultLanguage(DWORD value) { __bitfield1 = (__bitfield1 &
0xffffffffffff0000) | (value << 0); return value; }
     DWORD fContextDigits() { return (__bitfield1 >> 16) & 0x1; }
     DWORD fContextDigits(DWORD value) { __bitfield1 = (__bitfield1 &
0xfffffffffffeffff) | (value << 16); return value; }
     DWORD fInvertPreBoundDir() { return (__bitfield1 >> 17) & 0x1; }
     DWORD fInvertPreBoundDir(DWORD value) { __bitfield1 = (__bitfield1 &
0xfffffffffffdffff) | (value << 17); return value; }
     DWORD fInvertPostBoundDir() { return (__bitfield1 >> 18) & 0x1; }
     DWORD fInvertPostBoundDir(DWORD value) { __bitfield1 = (__bitfield1 &
0xfffffffffffbffff) | (value << 18); return value; }
     DWORD fLinkStringBefore() { return (__bitfield1 >> 19) & 0x1; }
     DWORD fLinkStringBefore(DWORD value) { __bitfield1 = (__bitfield1 &
0xfffffffffff7ffff) | (value << 19); return value; }
     DWORD fLinkStringAfter() { return (__bitfield1 >> 20) & 0x1; }
     DWORD fLinkStringAfter(DWORD value) { __bitfield1 = (__bitfield1 &
0xffffffffffefffff) | (value << 20); return value; }
     DWORD fNeutralOverride() { return (__bitfield1 >> 21) & 0x1; }
     DWORD fNeutralOverride(DWORD value) { __bitfield1 = (__bitfield1 &
0xffffffffffdfffff) | (value << 21); return value; }
     DWORD fNumericOverride() { return (__bitfield1 >> 22) & 0x1; }
     DWORD fNumericOverride(DWORD value) { __bitfield1 = (__bitfield1 &
0xffffffffffbfffff) | (value << 22); return value; }
     DWORD fLegacyBidiClass() { return (__bitfield1 >> 23) & 0x1; }
     DWORD fLegacyBidiClass(DWORD value) { __bitfield1 = (__bitfield1 &
0xffffffffff7fffff) | (value << 23); return value; }
     DWORD fReserved() { return (__bitfield1 >> 24) & 0xff; }
     DWORD fReserved(DWORD value) { __bitfield1 = (__bitfield1 &
0xffffffff00ffffff) | (value << 24); return value; }
 }
 alias tag_SCRIPT_CONTROL SCRIPT_CONTROL;

Which confusing me even more when input. It appears to be setter/getter properties providing some bit magic... I must say my bit arithmetic sucks, but thats not the point. And the point is, is it compatible with C API? This structure intended to be used with extern (Windows) functions... PS. what I actually trying to translate is Microsoft Uniscribe API (http://windowssdk.msdn.microsoft.com/en-us/library/ms776483.aspx)
Aug 05 2006
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Serg Kovrov" <kovrov no.spam> wrote in message 
news:eb32p6$tai$1 digitaldaemon.com...
 Hi all, I have a problem translating certain C structure to D. Here it is:

 typedef struct tag_SCRIPT_CONTROL { DWORD uDefaultLanguage :16; DWORD 
 fContextDigits :1; DWORD fInvertPreBoundDir :1; DWORD fInvertPostBoundDir 
 :1; DWORD fLinkStringBefore :1; DWORD fLinkStringAfter :1; DWORD 
 fNeutralOverride :1; DWORD fNumericOverride :1; DWORD fLegacyBidiClass 
 :1; DWORD fReserved :8; } SCRIPT_CONTROL;

It some sort of telling C compiler size of a struct member. I never used such technique before. htod output following:
 struct tag_SCRIPT_CONTROL
 {
     DWORD __bitfield1;
     DWORD uDefaultLanguage() { return (__bitfield1 >> 0) & 0xffff; }
     DWORD uDefaultLanguage(DWORD value) { __bitfield1 = (__bitfield1 & 
 0xffffffffffff0000) | (value << 0); return value; }
     DWORD fContextDigits() { return (__bitfield1 >> 16) & 0x1; }
     DWORD fContextDigits(DWORD value) { __bitfield1 = (__bitfield1 & 
 0xfffffffffffeffff) | (value << 16); return value; }
     DWORD fInvertPreBoundDir() { return (__bitfield1 >> 17) & 0x1; }
     DWORD fInvertPreBoundDir(DWORD value) { __bitfield1 = (__bitfield1 & 
 0xfffffffffffdffff) | (value << 17); return value; }
     DWORD fInvertPostBoundDir() { return (__bitfield1 >> 18) & 0x1; }
     DWORD fInvertPostBoundDir(DWORD value) { __bitfield1 = (__bitfield1 & 
 0xfffffffffffbffff) | (value << 18); return value; }
     DWORD fLinkStringBefore() { return (__bitfield1 >> 19) & 0x1; }
     DWORD fLinkStringBefore(DWORD value) { __bitfield1 = (__bitfield1 & 
 0xfffffffffff7ffff) | (value << 19); return value; }
     DWORD fLinkStringAfter() { return (__bitfield1 >> 20) & 0x1; }
     DWORD fLinkStringAfter(DWORD value) { __bitfield1 = (__bitfield1 & 
 0xffffffffffefffff) | (value << 20); return value; }
     DWORD fNeutralOverride() { return (__bitfield1 >> 21) & 0x1; }
     DWORD fNeutralOverride(DWORD value) { __bitfield1 = (__bitfield1 & 
 0xffffffffffdfffff) | (value << 21); return value; }
     DWORD fNumericOverride() { return (__bitfield1 >> 22) & 0x1; }
     DWORD fNumericOverride(DWORD value) { __bitfield1 = (__bitfield1 & 
 0xffffffffffbfffff) | (value << 22); return value; }
     DWORD fLegacyBidiClass() { return (__bitfield1 >> 23) & 0x1; }
     DWORD fLegacyBidiClass(DWORD value) { __bitfield1 = (__bitfield1 & 
 0xffffffffff7fffff) | (value << 23); return value; }
     DWORD fReserved() { return (__bitfield1 >> 24) & 0xff; }
     DWORD fReserved(DWORD value) { __bitfield1 = (__bitfield1 & 
 0xffffffff00ffffff) | (value << 24); return value; }
 }
 alias tag_SCRIPT_CONTROL SCRIPT_CONTROL;

Which confusing me even more when input. It appears to be setter/getter properties providing some bit magic... I must say my bit arithmetic sucks, but thats not the point. And the point is, is it compatible with C API? This structure intended to be used with extern (Windows) functions...

Wow, that's amazing; I didn't know htod would translate bitfields to properties like that. It should be compatible with the C API, since that's what C bitfields do for you behind the scenes - shifting and masking. And the positions look right. About the only thing I can see that might not work as in C is assigning a value to a bitfield larger than it can hold - for instance, setting uDefaultLanguage to 0x10000 would set bit 17, one beyond the top bit of the field. The solution of course would be to mask out the value to the size of the field. Might want Walter to see this.
Aug 05 2006
parent reply Serg Kovrov <kovrov no.spam> writes:
Jarrett Billingsley wrote:
 Wow, that's amazing; I didn't know htod would translate bitfields to 
 properties like that.  It should be compatible with the C API, since that's 
 what C bitfields do for you behind the scenes - shifting and masking.  And 
 the positions look right.

Thanks for reply, Jarrett, I hope it is. I actually can't test it right now as Uniscribe is quite complicated subject, and I just started investigating it... As/if I get some results, I'll post it (and perhaps bindings to the API) here. -- serg.
Aug 06 2006
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Serg Kovrov" <kovrov no.spam> wrote in message 
news:eb5rcb$2nh$1 digitaldaemon.com...

 Thanks for reply, Jarrett, I hope it is.

 I actually can't test it right now as Uniscribe is quite complicated 
 subject, and I just started investigating it... As/if I get some results, 
 I'll post it (and perhaps bindings to the API) here.

I worked up a simple example with some oddly-sized bitfields, and it does seem to work - I can link to the original C library using the htod'ed D module, and it can read the struct bitfields that D produces. This is using DMC though, so it might not be compatible with other compilers. Hopefully other compilers order bitfields the same way DMC does.
Aug 06 2006
parent Mike Parker <aldacron71 yahoo.com> writes:
Jarrett Billingsley wrote:
 "Serg Kovrov" <kovrov no.spam> wrote in message 
 news:eb5rcb$2nh$1 digitaldaemon.com...
 
 Thanks for reply, Jarrett, I hope it is.

 I actually can't test it right now as Uniscribe is quite complicated 
 subject, and I just started investigating it... As/if I get some results, 
 I'll post it (and perhaps bindings to the API) here.

I worked up a simple example with some oddly-sized bitfields, and it does seem to work - I can link to the original C library using the htod'ed D module, and it can read the struct bitfields that D produces. This is using DMC though, so it might not be compatible with other compilers. Hopefully other compilers order bitfields the same way DMC does.

It would be nice if the C standard specified ordering for bitfields, but it's one of the many items left up to the compiler. That's why any solution you use in D to implement them has the potential to break when interacting with C output from different compilers. I'm not sure what the reality is, though.
Aug 06 2006