Golang fmt.Println是否可以更改数组的值?

时间:2019-12-31 02:38:14

标签: 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.Println在相同的x.c [0]中两次,但是得到了不同的结果。为什么?

2 个答案:

答案 0 :(得分:2)

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

使用不同的值运行几次,然后检查位模式。您将得到一个LSB​​始终为5的值。您正在从其中放置了int32值5的存储位置读取int8。其余三个字节是堆栈剩余值。 / p>

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

答案 1 :(得分:0)

您的代码在go playground中正常工作。 输出始终为您提供5fmt.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