FMT.Println 可以更改数组的值吗?

  • 本文关键字:数组 Println FMT go
  • 更新时间 :
  • 英文 :

var x struct {
a bool
b int16
c []int32
}
func main() {
//a := []int32{1 << 9}
//x.c = a
pb := (*[]int8)(unsafe.Pointer(uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.c)))
*pb = []int8{5}
println(x.c[0])  // 5
println(x.c[0])  // 5
fmt.Println(x.c[0])  // 5
fmt.Println(x.c[0])  // 327685 why????????
}

FMT.两次打印相同的 x.c[0],但得到不同的结果。为什么?

使用unsafe时,您放置了一个int8片,其底层数组以堆栈形式分配,以代替int32片。因此,现在您遇到了这样一种情况:运行时认为存在一个int32值数组,但实际上该数组是int8值的数组。因此,当fmt.Println从中读取时,您会读取包含您放置在那里的5的字节,以及碰巧在那里的任何垃圾。

使用不同的值运行几次,并检查位模式。您将获得一个 LSB 始终为 5 的值。您正在从放置int8值 5 的内存位置读取int32。其余三个字节是堆栈剩余值。

如果使用[]int8{5,0,0,0}初始化切片,则始终会得到 5。

您的代码在go playground中运行良好。 输出始终为您提供5.fmt.Println不会更改x.c[0]

法典:

package main
import (
"fmt"
"unsafe"
)
var x struct {
a bool
b int16
c []int32
}
func main() {
//a := []int32{1 << 9}
//x.c = a
pb := (*[]int8)(unsafe.Pointer(uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.c)))
*pb = []int8{5}
println(x.c[0])     // 5
println(x.c[0])     // 5
fmt.Println(x.c[0]) // 5
fmt.Println(x.c[0]) // 327685 why????????
}

输出:

5
5
5
5

链接: https://play.golang.org/p/8l1Vj9of2vR

最新更新