unsafe标准库包
func Alignof(variable ArbitraryType) uintptr
。 此函数用来取得一个值在内存中的地址对齐保证(address alignment guarantee)。 注意,同一个类型的值做为结构体字段和非结构体字段时地址对齐保证可能是不同的。 当然,这和具体编译器的实现有关。对于目前的标准编译器(go 1.18),同一个类型的值做为结构体字段和非结构体字段时的地址对齐保证总是相同的。 gccgo
编译器对这两种情形是区别对待的。
package main
import (
"fmt"
"unsafe"
)
func main() {
var x struct {
a int64
b bool
c string
}
fmt.Println(unsafe.Alignof(x.a)) //8
fmt.Println(unsafe.Alignof(x.b)) //1
fmt.Println(unsafe.Alignof(x.c)) //8
}
地址对齐保证
为了充分使用CPU
的指令并获得最佳性能,为给指定类型的值分配的内存块(起始)地址必须是一个整数N
的倍数,则N
称为该类型的值的(内存)地址对齐保证,或者简单的称为该类型的对齐保证。我们也可以说,这个类型的可寻址值的地址确保是N
字节对齐的。
事实上,每种类型拥有两个对其保证,一种当它作为其他类型(struct)
的字段,另一种是针对其他情况(如当它作为一个变量的声明,数组元素的类型等等)。我称前者为类型的字段对齐保证,而称后者为类型的一般对齐保证。
对于一种类型,我们可以调用unsafe.Algnof(t)
去获取它的一般对齐保证,其中t
是T
类型的无字段值,也可以调用unsafe.Algnof(x.t)
去获取它字段的对齐保证,其中x
是一个struct
的值,同时a
是类型T
的字段值。
标准库unsafe
中的函数调用总是在编译期间。
在运行期间,对于类型T
的值,我们可以调用reflect.TypeOf(t).Align()
去获取类型T
的一般对齐保证,也可以调用reflect.TypeOf(t).FieldAlign()
去获取类型T
字段的一般对齐保证。