Golang 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
为什么为什么为什么?插眼
分清栈上变量和字符串常量。
谜语人?
蹲一个大佬的回答
你自己用法姿势不对,正确的应该是这样吧: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语言中指针地址问题的一些专业解答:
-
指针的定义: Go语言中的指针是一个存储了另一个变量内存地址的变量。通过指针,你可以直接修改它所指向的变量的值。
-
指针的声明和使用: 使用
var ptr *Type
声明一个指针,其中Type
是指针所指向的变量的类型。你可以通过&
操作符获取变量的地址,通过*
操作符解引用指针以访问或修改它所指向的值。 -
指针的地址和值: 当你打印一个指针时,显示的是它所存储的地址。当你解引用一个指针并打印时,显示的是它所指向的变量的值。
-
指针的传递: 在函数调用中,如果你传递一个变量的值,那么函数接收的是该值的一个副本。而如果你传递的是该变量的指针,那么函数可以直接修改原始变量的值,因为函数接收的是指向原始变量的指针。
-
注意事项:
- 小心空指针解引用,这会导致运行时错误。
- 指针的使用可以提高程序的效率,但也增加了复杂性,因此应谨慎使用。
- Go语言的垃圾回收机制会处理不再被引用的内存,但不当的指针使用可能导致内存泄漏。
总之,Go语言中的指针地址是一个强大的工具,但也需要谨慎使用以避免潜在的错误和复杂性。