Go Unsafe Offsetof explained
概述
Golang unsafe.Offsetof 函数返回结构体中某个字段在结构体内的偏移量。函数签名如下:
func Offsetof(x ArbitraryType) uintptr
其中 x 的形式必须是 structValue.field。
Go unsafe.Offsetof 实战
type M struct {
x int8
z int8
y int64
}
m := M{}
fieldY := m.y
// invalid expression unsafe.Offsetof(fieldY)
println(unsafe.Offsetof(fieldY))
// 8
println(unsafe.Offsetof(m.y))
// 8
println(unsafe.Offsetof(M{}.y))
概述部分指出 Offsetof 函数接收的表达式的形式必须是 structValue.field,因此 unsafe.Offsetof(fieldY)
会报错。后面的两个都是符合要求的写法,但是他们为什么输出 8,而不是 2 呢?
如果按照常规想法,x 是结构体中第一个字段,因此偏移为 0,x 本身占用 1 个字节, 因此 z 的偏移为 1,z 也是占用一个字节,因此 y 的偏移为 2。
虽然这是符合大家的第一反应,然而事实却并非如此,由于内存对齐,导致 y 的实际偏移量为 8。如果不清楚内存对齐,建议去复习一下 unsafe.Alignof。
如果大家认真看了 unsafe.Alignof,那么就很清楚 x 和 z 都是 1 字节对齐的,因此他们的偏移分别为 0 和 1。但是 y 是 8 字节对齐(假设为 64 位操作系统),因此 z 和 y 之间会填充 6 个空字节(padding),从而让 y 满足 8 字节对齐。
一般有:unsafe.Offsetof(structValue.field) = N * unsafe.Alignof(structValue.field),其中 N 为整数。
type M struct {
x int16
z int16
y int16
}
m := M{}
// 0
println(unsafe.Offsetof(m.x))
// 2
println(unsafe.Offsetof(m.z))
// 4
println(unsafe.Offsetof(m.y))
x,z 和 y 都是 2 字节的,他们都是 2 字节对齐的,因此他们在结构体内的偏移分别为 0,2 和 4。
有问题吗?点此反馈!
温馨提示:反馈需要登录