Struct Filed Alignment

What's Filed Alignment

Let's check the following code

type MyStruct struct {
    A byte
    B int64
    C byte
}

type MyStruct2 struct {
    A int64
    B byte
    C byte
}


s := &MyStruct{}
s2 := &MyStruct2{}

fmt.Printf("\tOffset:    %d\n", unsafe.Offsetof(s.A))
fmt.Printf("\tOffset:    %d\n", unsafe.Offsetof(s.B))
fmt.Printf("\tOffset:    %d\n", unsafe.Offsetof(s.C))

fmt.Printf("\tOffset:    %d\n", unsafe.Offsetof(s2.A))
fmt.Printf("\tOffset:    %d\n", unsafe.Offsetof(s2.B))
fmt.Printf("\tOffset:    %d\n", unsafe.Offsetof(s2.C))

If we check the comments of function unsafe.Offsetof, we can find the following texts:

// Offsetof returns the offset within the struct of the field represented by x,

// which must be of the form structValue.field. In other words, it returns the

// number of bytes between the start of the struct and the start of the field.

// The return value of Offsetof is a Go constant if the type of the argument x

// does not have variable size.

As we can see, for the case of MyStruct, the memory padding is reflected in the offset. It's memory waist definitely. So, the solution of MyStruct2 is better

An Example From Golang Source Code

// go1.23/src/internal/abi/iface.go

type ITab struct {
    Inter *InterfaceType
    Type  *Type
    Hash  uint32     // copy of Type.Hash. Used for type switches.
    Fun   [1]uintptr // variable sized. fun[0]==0 means Type does not implement Inter.
}

The ITab struct is used by the struct of the non empty interface. The whole definition is like that

// go1.23/src/runtime/runtime2.go

type iface struct {
    tab  *itab
    data unsafe.Pointer
}

The ITab.Hash has only 4 bytes. So on the 64bit CPU platform, there would be memory padding for it for the memory alignment. But why NOT define ITab.Func before ITab.Hash, so that it can save around 4 bytes from padding?

That's because Fun [1]uintptr is actually a placeholder for a dynamically sized array of method function pointers. And the runtime would actually append more memory space at the end of the ITab struct.

References

  • Golang Source Code v1.23
  • Gemini-2.5-pro

results matching ""

    No results matching ""