从 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 中的更改将跨版本转移地址。它现在动态获取地址与手动硬编码值。