Interesting C header translation problem
Alex Rønne Petersen
alex at lycus.org
Tue Oct 30 03:05:28 PDT 2012
On 30-10-2012 10:41, Nick Sabalausky wrote:
> Came across this:
>
> #ifdef __GNUC__
> #define PACKED __attribute__((packed))
> #else
> #define PACKED
> #endif
>
> typedef enum {
> // Lots o' stuff
> } PACKED my_enum_t;
>
> typedef struct {
> // Lots o' stuff
> const void *ptr;
> } PACKED my_struct_t;
>
> There are a handful of interesting (read: annoying ;) ) problems that
> are (*ahem*) packed into that:
>
> 1. Totally different ABI based on whether or not the **C** side was
> compiled with a GNU compiler.
Absolutely fucking horrible API design. These matters are, if anything,
related to the system ABI, not the compiler ABI. Making the layout
depend on the compiler ABI makes any sort of sane interoperability with
the API from non-C languages virtually impossible to do reliably.
>
> 2. How to do conditional "align(1)" with minimal ugliness.
I can't think of anything that doesn't involve repetitive code or
mixins. But worse than that, it's not like you can detect what compiler
was used to build some random library.....
>
> 3. WTF does it even mean to have a packed enum?
Nothing.
>
> 4. Having a pointer at the end of a packed struct is asking for trouble
> according to D's docs ("The garbage collector assumes that pointers and
> references to gc allocated objects will be on size_t byte boundaries.
> If they are not, undefined behavior will result.") Probably nothing
> that can be done about this one, though, other than just expect the
> user to be careful.
More generally, a pointer that is not aligned on a 4-byte (on 32-bit
systems) or 8-byte (on 64-bit systems) boundary will not be picked up by
the GC. This can happen in many situations, e.g.:
struct S
{
align (1):
byte b;
int* p;
byte b;
byte b;
int* p;
}
And many other possible layouts.
The best way to deal with terrible APIs in this regard is to use
GC.addRoot() to keep such pointers alive. This does of course mean that
you have to use GC.removeRoot() to make it collectable again...
>
> 5. From what I can gather from GCC and DMD docs, it sounds like
> __attribute__((packed)) means:
>
> align(1) struct my_struct_t{
> align(1):
> // blah, blah, members
> }
>
> BUT, are there any other...ummm..."fun" surprises that could pop up and
> need to be taken into account?
It only implies the inner align, not the outer one. GCC has an aligned
attribute on variables that can be used to get the effect of the outer
one. But no, no real surprises or gotchas here.
>
> 6. The easy one: I'm pretty sure "const void *ptr" translates to
> "const(void)* ptr", right?
Yep.
>
> For the moment, my "solution" is to just include a note saying "Don't
> compile the *.c files with __GNUC__ defined" ;) But what would be the
> best realistic way to handle these issues? Any established practices?
>
Honestly, I don't know. I would go stab the original API designers in
the face and tell them to clean up their mess.
--
Alex Rønne Petersen
alex at lycus.org
http://lycus.org
More information about the Digitalmars-d-learn
mailing list