Go:位字段和位打包

huangapple go评论102阅读模式
英文:

Go: Bitfields and bit packing

问题

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

.. 或者类似于这样(为了更正式,请参考这里)。

所以问题是,如果我想在Go语言中“做”位域,最佳实践是什么?

英文:

The C language's bitfields provide a fairly convenient method of defining arbitrary-width fields within a structure (nevermind the problems with portability for a minute.) For example, here's a simple structure with a couple fields and a 'flag':

#pragma pack(push,1)
struct my_chunk{

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

Adding the #pragma statements packs this structure into a 32-bit word (ensuring that pointer manipulations of my_chunk pointers are aligned, for example, along with space savings).

Accessing each field is syntactically very nice:

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

The alternate way of doing this without the language's help is rather ugly and pretty much devolves into assembler. e.g. one solution is to have bitshift macros for each field you want to access:

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

#define get_field(p, f) ((*p)&amp;f)
#define set_field(p, f, v) (*p) = (v&lt;&lt;f) + (*p)&amp;(~f)

...
set_field(&amp;my_chunk, FIELD_A, 12345);

.. or something roughly like that (for more formality, take a look at this)

So the question is, if I want to "do" bitfields in go, what is the best practice for doing so?

答案1

得分: 14

"Go语言目前没有关于结构体位域的计划。"

"你可以编写一个Go包来实现这个功能,不需要使用汇编语言。"

英文:

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

You could write a Go package to do this; no assembler is required.

答案2

得分: 9

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

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条指令的函数调用来获取值,而随着时间的推移,这样的调用可能会被内联。

英文:

If the goal is just to have a very small struct, you'd probably just do:

package main

import &quot;fmt&quot;

type my_chunk uint32

func (c my_chunk) A() uint16 {
  return uint16((c &amp; 0xffff0000) &gt;&gt; 16) 
}

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

func main() {
  x := my_chunk(123)
  x.SetA(12)
  fmt.Println(x.A())
}

With the current 6g/8g, you're looking at a function call with ~6 instructions for the getter, and with time such calls will probably be inlined.

huangapple
  • 本文由 发表于 2011年4月27日 00:05:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/5793098.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定