Go42 icon indicating copy to clipboard operation
Go42 copied to clipboard

关于28.2 指针运算代码示例的错误

Open LeChauvet opened this issue 4 years ago • 1 comments

但是对于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)))。

LeChauvet avatar Dec 13 '20 11:12 LeChauvet

同意上面的观点,今天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

这样说明下,这里自动进行了内存对齐,比较好理解

dipelta avatar Dec 17 '20 13:12 dipelta