从 Go 中的字符串访问内存地址?
Accessing a Memory Address From a String in Go?
在 golang 中,我可以打印给定字符串的内存地址的值吗?
例如,如果运行下面的代码:
a := "A String"
fmt.Println(&a)
它打印 0x1040c108
.
如何获取 0x1040c108
之类的字符串并打印存储在内存中的该字符串的值?类似于 fmt.Println(*0x1040c108)
这可能吗?
是的!!您可以将地址存储在指针变量中并通过取消引用它来打印其值
i := "something"
ptr := &i
fmt.Println(*ptr)
为了使用硬编码地址访问内存,例如 0x1040c108,您的程序必须能够访问该内存地址,否则,您将收到一条错误消息,提示无效指针的间接寻址或分段错误。
package main
import "C"
import (
"log"
"strconv"
"unsafe"
)
func main() {
// parse the string into an integer value
addr, _ := strconv.ParseInt("0x1040c108", 0, 64)
// cast the integer to a c string pointer
ptr := (*C.char)(unsafe.Pointer(uintptr(addr)))
// convert to a go string (this will segfault)
str := C.GoString(ptr)
// print it
log.Println(str)
}
这是可以做到的,但这是一个非常非常非常糟糕的主意。任何时候你导入 unsafe
包,你要么做错了什么,要么做一些非常顽固的事情。我什至对回答这个问题犹豫不决,但这里是。
https://play.golang.org/p/unkb-s8IzAo
package main
import (
"fmt"
"strconv"
"unsafe"
)
func main() {
// original example manually examined the printed address and used the value
// updated to preserve forward compatibility due to runtime changes shifting the address over time
hi := "HI"
// getting address as string dynamically to preserve compatibility
address := fmt.Sprint(&hi)
fmt.Printf("Address of var hi: %s\n", address)
// convert to uintptr
var adr uint64
adr, err := strconv.ParseUint(address, 0, 64)
if err != nil {
panic(err)
}
var ptr uintptr = uintptr(adr)
fmt.Printf("String at address: %s\n", address)
fmt.Printf("Value: %s\n", ptrToString(ptr))
}
func ptrToString(ptr uintptr) string {
p := unsafe.Pointer(ptr)
return *(*string)(p)
}
是的,这几乎是从 unsafe
godoc 中逐行提取的。 https://godoc.org/unsafe
还要注意 if/when 你的内存引用不是 go 字符串,一切都会灾难性地崩溃。 go vet
被配置为向您发送愤怒的消息,强调这确实是一个坏主意。
更新:从 go 1.15.1 开始,将 playground 上的示例更新为 运行,playground 或 go 本身已经改变了内存寻址的方式。或者更可能的情况是,核心 libs/runtime 中的更改将跨版本转移地址。它现在动态获取地址与手动硬编码值。
在 golang 中,我可以打印给定字符串的内存地址的值吗?
例如,如果运行下面的代码:
a := "A String"
fmt.Println(&a)
它打印 0x1040c108
.
如何获取 0x1040c108
之类的字符串并打印存储在内存中的该字符串的值?类似于 fmt.Println(*0x1040c108)
这可能吗?
是的!!您可以将地址存储在指针变量中并通过取消引用它来打印其值
i := "something"
ptr := &i
fmt.Println(*ptr)
为了使用硬编码地址访问内存,例如 0x1040c108,您的程序必须能够访问该内存地址,否则,您将收到一条错误消息,提示无效指针的间接寻址或分段错误。
package main
import "C"
import (
"log"
"strconv"
"unsafe"
)
func main() {
// parse the string into an integer value
addr, _ := strconv.ParseInt("0x1040c108", 0, 64)
// cast the integer to a c string pointer
ptr := (*C.char)(unsafe.Pointer(uintptr(addr)))
// convert to a go string (this will segfault)
str := C.GoString(ptr)
// print it
log.Println(str)
}
这是可以做到的,但这是一个非常非常非常糟糕的主意。任何时候你导入 unsafe
包,你要么做错了什么,要么做一些非常顽固的事情。我什至对回答这个问题犹豫不决,但这里是。
https://play.golang.org/p/unkb-s8IzAo
package main
import (
"fmt"
"strconv"
"unsafe"
)
func main() {
// original example manually examined the printed address and used the value
// updated to preserve forward compatibility due to runtime changes shifting the address over time
hi := "HI"
// getting address as string dynamically to preserve compatibility
address := fmt.Sprint(&hi)
fmt.Printf("Address of var hi: %s\n", address)
// convert to uintptr
var adr uint64
adr, err := strconv.ParseUint(address, 0, 64)
if err != nil {
panic(err)
}
var ptr uintptr = uintptr(adr)
fmt.Printf("String at address: %s\n", address)
fmt.Printf("Value: %s\n", ptrToString(ptr))
}
func ptrToString(ptr uintptr) string {
p := unsafe.Pointer(ptr)
return *(*string)(p)
}
是的,这几乎是从 unsafe
godoc 中逐行提取的。 https://godoc.org/unsafe
还要注意 if/when 你的内存引用不是 go 字符串,一切都会灾难性地崩溃。 go vet
被配置为向您发送愤怒的消息,强调这确实是一个坏主意。
更新:从 go 1.15.1 开始,将 playground 上的示例更新为 运行,playground 或 go 本身已经改变了内存寻址的方式。或者更可能的情况是,核心 libs/runtime 中的更改将跨版本转移地址。它现在动态获取地址与手动硬编码值。