Go:Bitfields和bit packing

Roo*_*oke 8 go bit-fields

C语言的位域提供了一种在结构中定义任意宽度字段的相当方便的方法(永远不要在一分钟内解决可移植性问题.)例如,这是一个带有几个字段和'flag'的简单结构:

#pragma pack(push,1)
struct my_chunk{

    unsigned short fieldA: 16;
    unsigned short fieldB: 15;
    unsigned short fieldC:  1;
};
#pragma pop()
Run Code Online (Sandbox Code Playgroud)

添加#pragma语句将此结构打包成一个32位字(确保指针的指针操作my_chunk对齐,例如,节省空间).

访问每个字段在语法上非常好:

struct my_chunk aChunk;
aChunk.fieldA = 3;
aChunk.fieldB = 2;
aChunk.fieldC = 1;
Run Code Online (Sandbox Code Playgroud)

在没有语言帮助的情况下执行此操作的替代方法相当丑陋,并且几乎可以转换为汇编程序.例如,一种解决方案是为要访问的每个字段设置bitshift宏:

#define FIELD_A  0xFF00
#define FIELD_B  0x00FE
#define FIELD_C  0x0001

#define get_field(p, f) ((*p)&f)
#define set_field(p, f, v) (*p) = (v<<f) + (*p)&(~f)

...
set_field(&my_chunk, FIELD_A, 12345);
Run Code Online (Sandbox Code Playgroud)

..或类似的东西(为了更正式,看看这个)

所以问题是,如果我想在go中"做"bitfields,这样做的最佳做法是什么?

pet*_*rSO 10

"Go目前还没有针对struct bitfields的计划."

你可以写一个Go包来做这件事; 不需要汇编程序.


Kyl*_*e C 8

如果目标只是拥有一个非常小的结构,你可能只是这样做:

package main

import "fmt"

type my_chunk uint32

func (c my_chunk) A() uint16 {
  return uint16((c & 0xffff0000) >> 16) 
}

func (c *my_chunk) SetA(a uint16) {
  v := uint32(*c)
  *c = my_chunk((v & 0xffff) | (uint32(a) << 16))
}

func main() {
  x := my_chunk(123)
  x.SetA(12)
  fmt.Println(x.A())
}
Run Code Online (Sandbox Code Playgroud)

使用当前的6g/8g,您正在查看带有~6个getter指令的函数调用,并且随着时间的推移这些调用可能会被内联.

  • 只是一个附录:我尝试用一​​个结构(而不​​是只有一个'chunk'变量)用uint16和uint32来做这个,不幸的是go给出了一个Sizeof()= 8,而不是结构的6.除此之外,一个大的(迟来的)谢谢你的回答,这是非常有帮助的 (2认同)
  • 是的,使用结构,成员可能是单词对齐的.如果您已经使用"不安全",则可以使用[3] uint16并使用"(*uint32)(unsafe.Pointer(&val [1]))"获取uint32部分,这可以避免打包/拆包的成本,但它有点难看. (2认同)