Bitfields are a useful feature for low-level tasks like OS development in C. However, Go's language specification does not include native support for bitfields.
C Example:
This C structure uses bitfields to pack data efficiently:
structvector_desc_t {
intflags: 16; // Bitfield: OR of VECDESC_FL_* defines (16 bits)unsigned intcpu: 1; // Bitfield (1 bit)unsigned intintno: 5; // Bitfield (5 bits)intsource: 8; // Bitfield: Interrupt mux flags (used when not shared, 8 bits)shared_vector_desc_t*shared_vec_info; // Pointer (used when VECDESC_FL_SHARED)vector_desc_t*next; // Pointer
};The numbers (16, 1, 5, 8) specify the exact number of bits each field occupies in memory.
Emulating Bitfields in Go
While Go lacks direct language-level support for bitfields, we can achieve similar functionality through code generation. This approach manually implements the bit manipulation operations.
The Go team exemplifies this technique in the https://cs.opensource.google/go/x/text/+/refs/tags/v0.28.0:internal/gen/bitfield/bitfield.go. For instance, code like this:
typemyUint8uint8typetest1struct { // Represents 28 bits of datafoouint16`bitfield:",fob"`// Tag hints for field "foo" with getter "fob"Barint8`bitfield:"5,baz"`// Tag: occupies 5 bits, getter named "baz"Foouint64// Regular field (whole uint64)barmyUint8`bitfield:"3"`// Tag: occupies 3 bits (default getter "bar")Boolbool`bitfield:""`// Tag: occupies 1 bit (default getter "Bool")Bazint8`bitfield:"3"`// Tag: occupies 3 bits (default getter "Baz")
}Can be processed by a generator to produce methods that manipulate the bits within a single underlying integer type (here, uint32 for the bitfields):
typetest1uint32// Underlying type holding the packed bitsfunc (ttest1) fob() uint16 { // Getter for field 'foo' (tag defined name "fob")returnuint16((t>>16) &0xffff) // Shift and mask for bits 16-31
}
func (ttest1) baz() int8 { // Getter for field 'Bar' (tag defined name "baz")returnint8((t>>11) &0x1f) // Shift and mask for 5 bits at pos 11
}
func (ttest1) bar() myUint8 { // Getter for field 'bar' (type myUint8)returnmyUint8((t>>8) &0x7) // Shift and mask for 3 bits at pos 8
}
func (ttest1) Bool() bool { // Getter for field 'Bool' (1 bit)constbit=1<<7// Bit mask for position 7returnt&bit==bit// Check if bit at pos 7 is set
}
func (ttest1) Baz() int8 { // Getter for field 'Baz'returnint8((t>>4) &0x7) // Shift and mask for 3 bits at pos 4
}Memory alignment
By default, the most of compilers respect that memory alignment:
Size = ceil(bits ÷ unit_bits)+ padding for larger members.
(Unit size = sizeof(unsigned int), typically 32 bits).
Bitfields are a useful feature for low-level tasks like OS development in C. However, Go's language specification does not include native support for bitfields.
C Example:
This C structure uses bitfields to pack data efficiently:
The numbers (
16, 1, 5, 8) specify the exact number of bits each field occupies in memory.Emulating Bitfields in Go
While Go lacks direct language-level support for bitfields, we can achieve similar functionality through code generation. This approach manually implements the bit manipulation operations.
The Go team exemplifies this technique in the https://cs.opensource.google/go/x/text/+/refs/tags/v0.28.0:internal/gen/bitfield/bitfield.go. For instance, code like this:
Can be processed by a generator to produce methods that manipulate the bits within a single underlying integer type (here, uint32 for the bitfields):
Memory alignment
By default, the most of compilers respect that memory alignment: