如何在Go中访问C语言的位域?

5

我有一个结构体,如下所示:

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

现在通过cgo我想要访问foo - 但是找不到任何关于如何这样做的文档。

简单地写下v := ms.foo会提示没有该字段或方法


我怀疑你能否做到:你可能必须自己进行位操作。 - Volker
但是如何实现(不写更多的C代码)? - abergmeier
2
@abergmeier:Golang 也有位运算符:https://yourbasic.org/golang/bitwise-operator-cheat-sheet/ - Sergio Tulentsev
位运算符只有在我有一个字段可以访问时才能帮助我。 - abergmeier
ms & 0x80 != 0ms & 0x7f 有什么问题? - Volker
澄清一下 - msMASK_SETTINGS 的一个实例。如果我直接访问它,它的类型是 _Ctype_struct_MASK_SETTINGS,因此无法进行移位等操作。当然,我可以编写一个 C 函数,将 foobar 组合成 uint32_t 并在 Go 中使用该值。我想知道是否有任何机会在不编写 C 代码的情况下使用位域。如果这不是您的意思,请说明一下。 - abergmeier
1个回答

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读取a.packed,然后进行位操作或使用位域实现之一
我告诉过你,你不会喜欢这个答案。 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接