1 回答
TA贡献1862条经验 获得超6个赞
uintptr(data)不正确:它从data(0 of type uint)获取值并将其转换为unitptrtype — 产生转换为另一种类型的相同值 — 在 x86 上产生空指针。
请注意,Go 不是 C,并且您不能真正玩带有指针的肮脏游戏,或者更确切地说,您可以,但只能通过使用unsafe内置包及其Pointer类型void*(指向数据存储器中的某个位置)块)在 C 中。
你需要的是类似的东西
import "unsafe"
var (
data [2]byte
length uint32
)
ret, _, e := procReadProcessMemory.Call(uintptr(handle), uintptr(i),
uintptr(unsafe.Pointer(&data[0])),
2, uintptr(unsafe.Pointer(&length))) // read 2 bytes
观察这里做了什么:
声明了一个“两字节数组”类型的变量;
取这个数组第一个元素的地址;
该地址被类型转换为类型
unsafe.Pointer
;然后将获得的值类型转换为
uintptr
。
需要最后两个步骤,因为 Go 具有垃圾收集功能:
在 Go 中,当你在内存中获取一个值的地址并将其存储在一个变量中时,GC 知道这个“隐式”指针,并且即使它变得无法访问,该地址的值也不会被垃圾收集保存其地址的值是唯一的引用。
即使您使该地址值丢失了它所维护的类型信息——通过将其类型转换为
unsafe.Pointer
,新值仍会被 GC 考虑并且表现得像包含地址的“正常”值——如上所述。通过将此类值类型转换为
uintptr
您可以让 GC 停止将其视为指针。因此,这种类型仅适用于 FFI/互操作。换句话说,在
var data [2]byte a := &data[0] p := unsafe.Pointer(a) i := uintptr(p)
中的值只有三个引用
data
:该变量本身a
和p
,但不是i
。
在处理调用外部代码时,您应该考虑这些规则,因为您永远不应该传递unitptr
-typed 值:它们仅用于将数据编组到被调用的函数并将其解组回来,并且必须“在现场”使用 - 在与它们从/到类型转换的值相同的范围。
另请注意,在 Go 中,您不能只获取整数类型变量的地址并将该地址提供给需要指向适当大小的内存块的指针的函数。您必须处理字节数组,并且在被调用函数写入数据后,您需要将其显式转换为所需类型的值。这就是为什么 Go 中没有“类型转换”而只有“类型转换”:您不能通过类型转换重新解释值的数据类型,uintptr(unsafe.Pointer)
对于 FFI/互操作而言,(和返回)是一个显着的例外,即使在这种情况下,您也基本上将指针转换为指针,只需将其通过 GC 边界传输即可。
要“序列化”和“反序列化”整数类型的值,您可以使用encoding/binary
标准包或手卷简单的简单函数,这些函数执行按位移位和or
-s 等;-)
2015-10-05,根据 James Henstridge 的建议更新。
请注意,在函数返回并发出ret
信号后,您必须检查length
变量的值没有错误。
- 1 回答
- 0 关注
- 441 浏览
添加回答
举报