golang 的指针地址问题

2021-01-28 22:10:17 +08:00
 yellowmarlboro
	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
2148 次点击
所在节点    Go 编程语言
12 条回复
yellowmarlboro
2021-01-28 23:37:31 +08:00
已经了解!
End
iQXQZX
2021-01-28 23:42:38 +08:00
为什么为什么为什么?插眼
iamzuoxinyu
2021-01-28 23:56:20 +08:00
分清栈上变量和字符串常量。
koujyungenn
2021-01-29 09:12:21 +08:00
@yellowmarlboro 谜语人?
kakach
2021-01-29 09:31:28 +08:00
蹲一个大佬的回答
kiddingU
2021-01-29 09:55:23 +08:00
你自己用法姿势不对,正确的应该是这样吧:unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&s0)))
yuguorui96
2021-01-29 09:55:26 +08:00
没翻源码,花了几分钟看了下汇编。

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

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

至于为啥 unsafe.Pointer 显示的结果是一致的,我个人猜测是因为字符串常量池(这个得去翻 Golang 的编译器,一会儿早上有会就不深挖了),即相同的字符串不会在内存中存在两次,有多次引用就把上面 data 的指针指向实际存储数据的 backing store 。这是一个常见优化,Python 中也存在。
Dganzh
2021-01-29 09:58:57 +08:00
字符串实际是一个**stuct
struct string {
byte* str;
intgo len;
}

大小就是 16
unsafe.Sizeof(s0) == 16
kiddingU
2021-01-29 10:56:36 +08:00
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
})
kiddingU
2021-01-29 11:08:00 +08:00
@yuguorui96 编译一下,可以看到,golang 对于相同的字符串确实是做了优化处理,只存一份的
iQXQZX
2021-01-29 11:16:12 +08:00
@kiddingU 学到了
yellowmarlboro
2021-02-03 20:02:34 +08:00
下棋的时候翻出答案就没来得及回具体解决,抱歉~
@kiddingU @yuguorui96 @Dganzh 等大佬都回答的要比我好!
多谢各位~

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/749359

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX