如何在Go中访问C位域

时间:2019-06-05 11:02:34

标签: go cgo

我有一个像这样的结构:

typedef struct st_MASK_SETTINGS
{
  uint32_t foo  : 1;
  uint32_t bar  : 7;
} MASK_SETTINGS

现在通过cgo我想访问foo-但找不到任何文档。

天真v := ms.foo抱怨has no field or method

1 个答案:

答案 0 :(得分:1)

好吧,你不会喜欢这个答案,但是

  1. 没有便携式方法来执行此操作,因为在C和C ++中位域打包都是“实现定义的”,并且
  2. Go中对位域的支持似乎很糟糕(也许由于#1)。

首先,在每个现有的C和C ++标准中,位域的布局都是实现定义的。这意味着没有一个标准指定如何打包位字段定义中的位(即它们应该去哪里)-这完全取决于编译器。在给出一些编译器样本的情况下,您可能会发现它们的布局是在实践中,但是您将深入研究未定义的行为领域。

我们正在bug #83784下的gcc中解决这个问题(“我”的意思是Andrew Pinski),我希望在gcc 10或11中我们将有一个最佳解决方案。要明确的是,现在有一个解决方案-它使用联合并定义打包和解压缩函数来读取每个位域,然后将数据手动放入内存中。问题是,当您正确地猜测gcc使用的位布局时,该功能应变为无操作且“可编译”。目前这还没有发生。

示例:

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;
}

执行此操作后,您可以“打包”位字段,从Go中读取打包的内容,然后对它进行位拨弄或使用one of the bitfield implementations

我告诉过你,你不想要答案。 :)