Golang Go语言中使用 unsafe 转换 int 为 byte 切片,在通过打印读 byte 切片时数据发生变化

发布于 1周前 作者 phonegap100 来自 Go语言
func main() {
	n := 1
nbytes := i2bin(n)

for i := 0; i < len(nbytes); i++ {
	fmt.Printf("value: %v,addr: %p", nbytes[i], &nbytes[i])
}

}

func i2bin(i int) []byte { sh := &reflect.SliceHeader{Len: 8, Cap: 8, Data: uintptr(unsafe.Pointer(&i))} return ([]byte)(unsafe.Pointer(sh)) }

如题,转换完成后数据是正常的为: [0]:0x1 [1]:0x0 [2]:0x0 [3]:0x0 [4]:0x0 [5]:0x0 [6]:0x0 [7]:0x0

进入循环,第一次打印数组结束数据就变成了: [0]:0x9 [1]:0x10 [2]:0xa3 [3]:0x0 [4]:0x0 [5]:0x0 [6]:0x0 [7]:0x0

为什么会发生变化呢?

golang: v1.18.3 windows


Golang Go语言中使用 unsafe 转换 int 为 byte 切片,在通过打印读 byte 切片时数据发生变化

更多关于Golang Go语言中使用 unsafe 转换 int 为 byte 切片,在通过打印读 byte 切片时数据发生变化的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

按值传进去的,在栈上。

更多关于Golang Go语言中使用 unsafe 转换 int 为 byte 切片,在通过打印读 byte 切片时数据发生变化的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html




i2bin写在 main 函数中确实访问后没有变化。通过指针传入 int 也可以达到这个效果,意味着这片内存会逃逸到堆上。

所以不论是在i2bin中创建完的 SliceHeader 还是main中响应过程中复制的切片,uintptr指向的是同一片内存空间。在函数执行完毕后main函数的切片依旧指向的是栈上的空间,但是这片空间已经被 runtime 标记为可回收的空间并且确实被回收了。

var sb = make([]byte, 8)
*(*int)(unsafe.Pointer(&sb[0])) = i

而且可以不取 0 ,这样可以避免一次中间内存的分配

在Golang中,使用unsafe包进行类型转换通常是不被推荐的做法,因为它绕过了Go的类型安全机制,可能会导致不可预测的行为,包括数据损坏或程序崩溃。具体到你的问题,将int转换为byte切片并打印时数据发生变化,这很可能是因为类型转换和内存管理不当导致的。

首先,intbyte切片在内存中的布局和大小可能不同,直接通过unsafe.Pointer进行转换可能会读取到错误的内存区域。其次,即使你正确地进行了转换,打印时也可能因为切片边界或内存对齐问题导致数据被错误解释。

一个更安全、更推荐的做法是使用标准库提供的函数进行类型转换和数据处理。例如,如果你想要将一个int的值转换为字节序列(例如,为了网络传输或文件存储),你可以使用encoding/binary包中的函数,如binary.Write,将int写入到一个bytes.Buffer中,然后再将其转换为byte切片。

总之,尽量避免使用unsafe包进行类型转换,除非你对Go的内存模型和类型系统有深入的理解,并且确信你的代码不会引入任何安全问题。对于大多数情况,使用标准库提供的函数和类型进行数据处理是更安全、更可靠的选择。

回到顶部