【问题标题】:Go: Bitfields and bit packingGo:位域和位打包
【发布时间】:2011-04-26 16:05:10
【问题描述】:

C 语言的位域提供了一种在结构中定义任意宽度字段的相当方便的方法(暂时不用考虑可移植性的问题。)例如,这是一个带有一对字段和一个“标志”的简单结构:

#pragma pack(push,1)
struct my_chunk{

    unsigned short fieldA: 16;
    unsigned short fieldB: 15;
    unsigned short fieldC:  1;
};
#pragma pop()

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

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

struct my_chunk aChunk;
aChunk.fieldA = 3;
aChunk.fieldB = 2;
aChunk.fieldC = 1;

在没有语言帮助的情况下执行此操作的另一种方法相当难看,并且几乎演变为汇编程序。例如一种解决方案是为您要访问的每个字段设置位移宏:

#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);

.. 或类似的东西(更正式的,请查看this

所以问题是,如果我想在 go 中“做”位域,这样做的最佳做法是什么?

【问题讨论】:

    标签: go bit-fields


    【解决方案1】:

    "There are no current plans for struct bitfields in Go."

    您可以编写一个 Go 包来执行此操作;不需要汇编程序。

    【讨论】:

    • 请注意,他并不是真的意味着必须使用汇编程序,而是当您必须手动.
    【解决方案2】:

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

    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())
    }
    

    在当前的 6g/8g 中,您正在查看一个带有约 6 条 getter 指令的函数调用,并且随着时间的推移,此类调用可能会被内联。

    【讨论】:

    • 只是一个附录:我尝试使用带有 uint16 和 uint32 的结构(而不​​仅仅是一个“块”变量)来执行此操作,不幸的是 go 给出了 Sizeof() = 8,而不是 6对于结构。除此之外,非常感谢您的回答,非常有帮助
    • 是的,结构体的成员很可能是字对齐的。如果您已经在使用“unsafe”,则可以使用 [3]uint16 并使用“(*uint32)(unsafe.Pointer(&val[1]))”获取 uint32 部分,这样可以避免打包/解包的成本,但是有点丑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-24
    • 1970-01-01
    • 1970-01-01
    • 2015-05-31
    • 1970-01-01
    相关资源
    最近更新 更多