Go42
Go42 copied to clipboard
关于28.2 指针运算代码示例的错误
但是对于v.j来说,怎么来得到它在内存中的地址呢?其实我们可以获取它相对于v的偏移量(unsafe.Sizeof可以为我们做这个事),但上面的代码并没有这样去实现。各位别急,一步步来。
var j *int64 = (*int64)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + uintptr(unsafe.Sizeof(int64(0)))))
其实我们已经知道v是有两个成员的,包括i和j,并且在定义中,i位于j的前面,而i是int32类型,也就是说i占4个字节。所以j是相对于v偏移了4个字节。您可以用uintptr(4)或uintptr(unsafe.Sizeof(int64(0)))来做这个事。unsafe.Sizeof方法用来得到一个值应该占用多少个字节空间。注意这里跟C的用法不一样,C是直接传入类型,而Go 语言是传入值。
以上这一段表述中将uintptr(4)等同于uintptr(unsafe.Sizeof(int64(0))),但其实uintptr(unsafe.Sizeof(int64(0)))==uintptr(8),但是这里var j *int64 = (*int64)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + uintptr(unsafe.Sizeof(int64(0)))))
是可以正确取到j的值,是因为这里发生了对齐,除了i本身占用4字节,还有4个字节由编译器进行填充,导致unsafe.Offsetof(v.j)和uintptr(unsafe.Sizeof(int64(0)))在64位机器上,值都是8。原文说j是相对于v偏移了4个字节,实际上是错误的,而且也没有说清楚为什么使用uintptr(unsafe.Sizeof(int64(0)))。
同意上面的观点,今天unsafe看了半天,估摸着这里说明好像是有点问题
fmt.Printf("int32所占大小:%d \n", unsafe.Sizeof(int32(0))) //4
fmt.Printf("int64所占大小:%d \n", unsafe.Sizeof(int64(0))) //8
fmt.Printf("v内存大小:%d \n", unsafe.Sizeof(*v)) //16
这样说明下,这里自动进行了内存对齐,比较好理解