Accessing a Memory Address From a String in Go?

huangapple go评论151阅读模式
英文:

Accessing a Memory Address From a String in Go?

问题

在Go语言中,可以通过给定的字符串打印内存地址的值吗?

例如,如果运行以下代码:

a := "A String"
fmt.Println(&a)

它会打印出0x1040c108

我该如何使用类似0x1040c108这样的字符串,并打印存储在该内存中的值?类似于fmt.Println(*0x1040c108)这样的操作。

这种操作是否可行?

英文:

In golang, can I print the value of a memory address from a given string?

For example, if run the following code:

a := "A String"
fmt.Println(&a)

It prints 0x1040c108.

How could I take a string such as 0x1040c108 and print the value of that string stored in the memory? Something like fmt.Println(*0x1040c108)

Is this possible?

答案1

得分: 13

这是可以做到的,但这是一个非常非常非常糟糕的主意。每当你导入unsafe包时,要么你做错了什么,要么你在做一些非常核心的事情。我对于回答这个问题都有些犹豫,但还是试试吧。

package main

import (
	"fmt"
	"strconv"
	"unsafe"
)

func main() {
	// 原始示例手动检查打印的地址并使用值
	// 由于运行时的更改会随着时间推移而移动地址,因此更新以保持向前兼容性

	hi := "HI"

	// 动态获取地址作为字符串以保持兼容性
	address := fmt.Sprint(&hi)

	fmt.Printf("变量 hi 的地址: %s\n", address)

	// 转换为 uintptr
	var adr uint64
	adr, err := strconv.ParseUint(address, 0, 64)
	if err != nil {
		panic(err)
	}
	var ptr uintptr = uintptr(adr)

	fmt.Printf("地址中的字符串: %s\n", address)
	fmt.Printf("值: %s\n", ptrToString(ptr))
}

func ptrToString(ptr uintptr) string {
	p := unsafe.Pointer(ptr)
	return *(*string)(p)
}

是的,这个示例几乎是从unsafe的godoc中逐行复制的。https://godoc.org/unsafe

还要注意,如果你的内存引用不是一个Go字符串,一切都将以灾难性的方式崩溃。而且go vet会配置为向你发送一条愤怒的消息,因为你这样做,这再次强调了这是一个糟糕的主意。

更新:更新示例以在Go 1.15.1上运行,playground或go本身已更改了内存寻址的方式。或者更有可能的情况是核心库/运行时的更改会导致地址在不同版本之间发生变化。现在它动态获取地址而不是手动硬编码值。

英文:

This can be done, but it is a really really REALLY bad idea. Anytime you are importing the unsafe package, you are either doing something wrong, or something really hardcore. I'm hesitant to even answer this, but here goes.

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)
}

And yes, this was pretty much taken almost line for line from the unsafe godoc. https://godoc.org/unsafe

Also note that if/when your memory reference is NOT a go string, everything will come crashing down catastrophically. And that go vet is configured to send you an angry message for doing this, reinforcing that this is indeed a bad idea.

UPDATE: Updated example to run on playground as of go 1.15.1, which either the playground or go itself has changed the way the memory is addressed. Or the more likely case that changes in core libs/runtime will shift the address across versions. It now dynamically obtains the address vs a manually hardcoded value.

答案2

得分: 2

package main

import "C"

import (
	"log"
	"strconv"
	"unsafe"
)

func main() {

	// 将字符串解析为整数值
	addr, _ := strconv.ParseInt("0x1040c108", 0, 64)

	// 将整数转换为C字符串指针
	ptr := (*C.char)(unsafe.Pointer(uintptr(addr)))

	// 转换为Go字符串(这将导致段错误)
	str := C.GoString(ptr)

	// 打印字符串
	log.Println(str)
}

这是一个Go语言的代码示例。它将一个十六进制字符串解析为整数值,然后将整数转换为C字符串指针。最后,它将C字符串指针转换为Go字符串,并打印出来。请注意,这段代码可能会导致段错误,因为它试图访问一个无效的内存地址。

英文:
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)
}

答案3

得分: 0

是的!你可以将地址存储在指针变量中,并通过解引用打印其值。

i := "something"
ptr := &i
fmt.Println(*ptr)

如果要访问一个硬编码的地址,比如 0x1040c108,你的程序必须有权限访问该内存地址,否则你将会收到一个指针无效或分段错误的错误提示。

英文:

Yes!! you can store the address in a pointer variable and print its value by derefrencing it

i := "something"
ptr := &i
fmt.Println(*ptr)

For accessing the memory using a hard coded address such as 0x1040c108, it is necessary for your program to have access to that memory address otherwise, you will get an error saying invalid indirection of a pointer or segmentation fault.

huangapple
  • 本文由 发表于 2017年5月4日 01:25:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/43766471.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定