Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access C bitfield in Go

Tags:

go

cgo

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.

like image 444
abergmeier Avatar asked Nov 07 '22 16:11

abergmeier


1 Answers

Well you won't like this answer, but

  1. there is no portable way to do this because bitfield packing is "implementation-defined" in both C and C++, and
  2. 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. :)

like image 159
Daniel Santos Avatar answered Nov 12 '22 13:11

Daniel Santos