问题
I have a struct like so:
typedef struct st_MASK_SETTINGS
{
uint32_t foo : 1;
uint32_t bar : 7;
} MASK_SETTINGS
Now through cgo I would like to access foo
- but cannot find any documentation how to do so.
Naive v := ms.foo
complains has no field or method
.
回答1:
Well you won't like this answer, but
- there is no portable way to do this because bitfield packing is "implementation-defined" in both C and C++, and
- bitfield support in Go seems fairly crappy (perhaps due to #1).
First of all, the layout of bitfields is implementation-defined in every existing C and C++ standard. This means that none of the standards specify how bits in a bitfield definition should be packed (i.e., where they should go) -- it's totally up to the compiler. You may find how they are laid out to be a certain way in practice given a few compiler samples, but you will be deep into undefined behavior territory.
We are working on this issue in gcc under bug #83784 (and by "we" I mean Andrew Pinski), and I'm hoping that in gcc 10 or 11 we'll have an optimal solution. To be clear, there is a solution now -- it is use a union and define pack and unpack functions to read each bitfield and manually put the data where it belongs in memory. The issue is that when you have properly guessed the bit layout gcc uses then the function should become no-ops and "compile-away". This is currently not happening.
Example:
union a {
struct {
int field1:12;
int field2:20;
};
int packed;
};
static union a a_pack(union a a)
{
union a ret = {0};
ret.packed = (a.field1 & ((1 << 12) - 1) << 20;
ret.packed |= a.field2 & ((1 << 20) - 1)
return ret;
}
static union a a_unpack(union a a)
{
union a ret = {0};
ret.field1 = a.packed >> 20;
ret.field2 = a.packed & ((1 << 20) - 1);
return ret;
}
Once you do this, you can "pack" your bitfield, read a.packed from Go and then either bit fiddle it or use one of the bitfield implementations.
I told you you wouldn't like the answer. :)
来源:https://stackoverflow.com/questions/56459197/how-to-access-c-bitfield-in-go