golang中复合类型,打印变量自身地址跟打印变量取地址之后的地址为何不同?

1. 运行环境

go version go1.15.4 linux/amd64

2. 问题描述?

package main

import (
    "fmt"
)

func main() {
    b := new(map[int]string)
    fmt.Printf("b: %p\n", b)
    fmt.Printf("&b: %p\n", &b)

    c := make(map[int]string)
    fmt.Printf("c: %p\n", c)
    fmt.Printf("&c: %p\n", &c)
}
/*
打印结果
b: 0xc0000ba020
&b: 0xc0000ba018
c: 0xc000098150
&c: 0xc0000ba030
*/

上述代码中打印的b和&b,c和&c为什么不一样呢?
b和c是变量b和c的地址,那另外两个是什么地址,有什么特殊含义吗?

补充

func (p *pp) printArg(arg interface{}, verb rune) {
    ...
    switch verb {
    case  'T':
        p.fmt.fmtS(reflect.TypeOf(arg).String())
        return
    case  'p':
        p.fmtPointer(reflect.ValueOf(arg), 'p')
        return
    }
    ...
}
func (p *pp) fmtPointer(value reflect.Value, verb rune) {
    var u uintptr
    switch value.Kind() {
    case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
        u = value.Pointer()
    default:
        p.badVerb(verb)
        return
    }
    ...
}

上述是一段fmt.Printf在打印%p时候的一段源码,可以看出,当打印数据为符合类型,函数,指针的时候%p返回的就是当前值的指针,也就是上述打印的b和c即为变量指针。 这时候&b和&c也就成为了指向指针变量的指针地址。
疑问:程序在打印&b和&c这两行时是否真正的分配内存空间了呢?
观察到的现象:从多次执行结果看,b与&b的地址总相差2(16进制),c与&c却相差甚远。(可能跟make和new的源码有关系)

// new的源码返
func newobject(typ *_type) unsafe.Pointer

// makemap的源码
func makemap_small() *hmap
最佳答案
package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

func main() {
    b := new([]int)
    fmt.Printf("底层数组地址:%p\n", b)
    fmt.Printf("b的地址: %p\n", &b)
    struct_ptr := unsafe.Pointer(&b)
    struct_b := (*reflect.SliceHeader)(struct_ptr)
    fmt.Println(struct_ptr)
    fmt.Printf("%#v\n", struct_b)

    c := make([]int, 2, 3)
    fmt.Printf("底层数组地址:%p\n", c)
    fmt.Printf("c的地址: %p\n", &c)
    struct_ptr = unsafe.Pointer(&c)
    struct_c := (*reflect.SliceHeader)(struct_ptr)
    fmt.Println(struct_ptr)
    fmt.Printf("%#v\n", struct_c)
}
/*
打印结果
底层数组地址:0xc000096060
b的地址: 0xc0000ce018
0xc0000ce018
&reflect.SliceHeader{Data:0xc000096060, Len:3789440, Cap:0}
底层数组地址:0xc0000ae0a8
c的地址: 0xc000096078
0xc000096078
&reflect.SliceHeader{Data:0xc0000ae0a8, Len:2, Cap:3}
*/
1年前 评论
讨论数量: 5

还有个疑问就是为啥地址打印出来是10位16进制数,而不是16位?(刚开始以为是vscode打印隐藏了,用goland也是一样,内存16GB,不知道跟内存大小是否有关)

1年前 评论
失色天空 1年前
失色天空 1年前
Andre_W (作者) (楼主) 1年前
package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

func main() {
    b := new([]int)
    fmt.Printf("底层数组地址:%p\n", b)
    fmt.Printf("b的地址: %p\n", &b)
    struct_ptr := unsafe.Pointer(&b)
    struct_b := (*reflect.SliceHeader)(struct_ptr)
    fmt.Println(struct_ptr)
    fmt.Printf("%#v\n", struct_b)

    c := make([]int, 2, 3)
    fmt.Printf("底层数组地址:%p\n", c)
    fmt.Printf("c的地址: %p\n", &c)
    struct_ptr = unsafe.Pointer(&c)
    struct_c := (*reflect.SliceHeader)(struct_ptr)
    fmt.Println(struct_ptr)
    fmt.Printf("%#v\n", struct_c)
}
/*
打印结果
底层数组地址:0xc000096060
b的地址: 0xc0000ce018
0xc0000ce018
&reflect.SliceHeader{Data:0xc000096060, Len:3789440, Cap:0}
底层数组地址:0xc0000ae0a8
c的地址: 0xc000096078
0xc000096078
&reflect.SliceHeader{Data:0xc0000ae0a8, Len:2, Cap:3}
*/
1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!