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,这样做的最佳做法是什么?
如果目标只是拥有一个非常小的结构,你可能只是这样做:
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指令的函数调用,并且随着时间的推移这些调用可能会被内联.