Golang Go语言中的指针地址问题

发布于 1周前 作者 htzhanglong 来自 Go语言

Golang Go语言中的指针地址问题

	s0 := “something”
s1 := “something”
s2 := “something”[7:]
fmt.Println(&s0, &s1, &s2)
fmt.Printf("%d \n", (*reflect.StringHeader)(unsafe.Pointer(&s0)).Data)
fmt.Printf("%d \n", (*reflect.StringHeader)(unsafe.Pointer(&s1)).Data)
fmt.Printf("%d \n", (*reflect.StringHeader)(unsafe.Pointer(&s2)).Data)

结果是

0xc00010a040 0xc00010a050 0xc00010a060
4974445 
4974445 
4974452
  • 为什么 & 出来的总差 16 ? unsafe.Pointer 是一样的?(请忽略切片的)

更多关于Golang Go语言中的指针地址问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

13 回复

已经了解!
End

更多关于Golang Go语言中的指针地址问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


为什么为什么为什么?插眼

分清栈上变量和字符串常量。

蹲一个大佬的回答

你自己用法姿势不对,正确的应该是这样吧:unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&s0)))

没翻源码,花了几分钟看了下汇编。

s0, s1, s2 之间的地址总差 16 是因为 String 在栈上的结构是:
struct String {
char *data;
int length;
};
sizeof(一个指针)+sizeof(一个 int)正好是 16 字节( 64 位环境下)。

又因为栈上变量都是编译器按序分配的,所以有了楼主看到的结果。

至于为啥 unsafe.Pointer 显示的结果是一致的,我个人猜测是因为字符串常量池(这个得去翻 Golang 的编译器,一会儿早上有会就不深挖了),即相同的字符串不会在内存中存在两次,有多次引用就把上面 data 的指针指向实际存储数据的 backing store 。这是一个常见优化,Python 中也存在。

字符串实际是一个**stuct
struct string {
byte* str;
intgo len;
}

大小就是 16
unsafe.Sizeof(s0) == 16

import (
github.com/davecgh/go-spew/spew
“reflect”
“unsafe”
)

func main() {
s0 := “something”
s1 := “something”
spew.Dump(&s0)
spew.Dump(&s1)
spew.Dump((*reflect.StringHeader)(unsafe.Pointer(&s0)))
spew.Dump((*reflect.StringHeader)(unsafe.Pointer(&s1)))
}

--------------
(*string)(0xc0001042b0)((len=9) “something”)
(*string)(0xc0001042c0)((len=9) “something”)
(*reflect.StringHeader)(0xc0001042b0)({
Data: (uintptr) 0x1101229,
Len: (int) 9
})
(*reflect.StringHeader)(0xc0001042c0)({
Data: (uintptr) 0x1101229,
Len: (int) 9
})

编译一下,可以看到,golang 对于相同的字符串确实是做了优化处理,只存一份的

下棋的时候翻出答案就没来得及回具体解决,抱歉~
等大佬都回答的要比我好!
多谢各位~

在Golang(Go语言)中,指针地址是一个核心概念,它允许你直接访问和操作内存中的变量值。以下是对Go语言中指针地址问题的一些专业解答:

  1. 指针的定义: Go语言中的指针是一个存储了另一个变量内存地址的变量。通过指针,你可以直接修改它所指向的变量的值。

  2. 指针的声明和使用: 使用var ptr *Type声明一个指针,其中Type是指针所指向的变量的类型。你可以通过&操作符获取变量的地址,通过*操作符解引用指针以访问或修改它所指向的值。

  3. 指针的地址和值: 当你打印一个指针时,显示的是它所存储的地址。当你解引用一个指针并打印时,显示的是它所指向的变量的值。

  4. 指针的传递: 在函数调用中,如果你传递一个变量的值,那么函数接收的是该值的一个副本。而如果你传递的是该变量的指针,那么函数可以直接修改原始变量的值,因为函数接收的是指向原始变量的指针。

  5. 注意事项

    • 小心空指针解引用,这会导致运行时错误。
    • 指针的使用可以提高程序的效率,但也增加了复杂性,因此应谨慎使用。
    • Go语言的垃圾回收机制会处理不再被引用的内存,但不当的指针使用可能导致内存泄漏。

总之,Go语言中的指针地址是一个强大的工具,但也需要谨慎使用以避免潜在的错误和复杂性。

回到顶部