V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
RayR
V2EX  ›  Go 编程语言

[golang] 使用 unsafe 转换 int 为 byte 切片,在通过打印读 byte 切片时数据发生变化

  •  
  •   RayR · 2022-07-19 09:38:23 +08:00 · 1116 次点击
    这是一个创建于 877 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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

    3 条回复    2022-07-27 10:05:43 +08:00
    joesonw
        1
    joesonw  
       2022-07-19 09:58:40 +08:00 via iPhone
    按值传进去的,在栈上。
    RayR
        2
    RayR  
    OP
       2022-07-19 10:21:48 +08:00
    @joesonw

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

    所以不论是在`i2bin`中创建完的 SliceHeader 还是`main`中响应过程中复制的切片,`uintptr`指向的是同一片内存空间。在函数执行完毕后`main`函数的切片依旧指向的是栈上的空间,但是这片空间已经被 runtime 标记为可回收的空间并且确实被回收了。
    lysS
        3
    lysS  
       2022-07-27 10:05:43 +08:00
    var sb = make([]byte, 8)
    *(*int)(unsafe.Pointer(&sb[0])) = i

    而且可以不取 0 ,这样可以避免一次中间内存的分配
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1279 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 17:26 · PVG 01:26 · LAX 09:26 · JFK 12:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.