1 回答

TA貢獻(xiàn)1862條經(jīng)驗(yàn) 獲得超6個(gè)贊
uintptr(data)不正確:它從data(0 of type uint)獲取值并將其轉(zhuǎn)換為unitptrtype — 產(chǎn)生轉(zhuǎn)換為另一種類型的相同值 — 在 x86 上產(chǎn)生空指針。
請(qǐng)注意,Go 不是 C,并且您不能真正玩帶有指針的骯臟游戲,或者更確切地說(shuō),您可以,但只能通過(guò)使用unsafe內(nèi)置包及其Pointer類型void*(指向數(shù)據(jù)存儲(chǔ)器中的某個(gè)位置)塊)在 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
觀察這里做了什么:
聲明了一個(gè)“兩字節(jié)數(shù)組”類型的變量;
取這個(gè)數(shù)組第一個(gè)元素的地址;
該地址被類型轉(zhuǎn)換為類型
unsafe.Pointer
;然后將獲得的值類型轉(zhuǎn)換為
uintptr
。
需要最后兩個(gè)步驟,因?yàn)?Go 具有垃圾收集功能:
在 Go 中,當(dāng)你在內(nèi)存中獲取一個(gè)值的地址并將其存儲(chǔ)在一個(gè)變量中時(shí),GC 知道這個(gè)“隱式”指針,并且即使它變得無(wú)法訪問(wèn),該地址的值也不會(huì)被垃圾收集保存其地址的值是唯一的引用。
即使您使該地址值丟失了它所維護(hù)的類型信息——通過(guò)將其類型轉(zhuǎn)換為
unsafe.Pointer
,新值仍會(huì)被 GC 考慮并且表現(xiàn)得像包含地址的“正常”值——如上所述。通過(guò)將此類值類型轉(zhuǎn)換為
uintptr
您可以讓 GC 停止將其視為指針。因此,這種類型僅適用于 FFI/互操作。換句話說(shuō),在
var data [2]byte a := &data[0] p := unsafe.Pointer(a) i := uintptr(p)
中的值只有三個(gè)引用
data
:該變量本身a
和p
,但不是i
。
在處理調(diào)用外部代碼時(shí),您應(yīng)該考慮這些規(guī)則,因?yàn)槟肋h(yuǎn)不應(yīng)該傳遞unitptr
-typed 值:它們僅用于將數(shù)據(jù)編組到被調(diào)用的函數(shù)并將其解組回來(lái),并且必須“在現(xiàn)場(chǎng)”使用 - 在與它們從/到類型轉(zhuǎn)換的值相同的范圍。
另請(qǐng)注意,在 Go 中,您不能只獲取整數(shù)類型變量的地址并將該地址提供給需要指向適當(dāng)大小的內(nèi)存塊的指針的函數(shù)。您必須處理字節(jié)數(shù)組,并且在被調(diào)用函數(shù)寫入數(shù)據(jù)后,您需要將其顯式轉(zhuǎn)換為所需類型的值。這就是為什么 Go 中沒有“類型轉(zhuǎn)換”而只有“類型轉(zhuǎn)換”:您不能通過(guò)類型轉(zhuǎn)換重新解釋值的數(shù)據(jù)類型,uintptr(unsafe.Pointer)
對(duì)于 FFI/互操作而言,(和返回)是一個(gè)顯著的例外,即使在這種情況下,您也基本上將指針轉(zhuǎn)換為指針,只需將其通過(guò) GC 邊界傳輸即可。
要“序列化”和“反序列化”整數(shù)類型的值,您可以使用encoding/binary
標(biāo)準(zhǔn)包或手卷簡(jiǎn)單的簡(jiǎn)單函數(shù),這些函數(shù)執(zhí)行按位移位和or
-s 等;-)
2015-10-05,根據(jù) James Henstridge 的建議更新。
請(qǐng)注意,在函數(shù)返回并發(fā)出ret
信號(hào)后,您必須檢查length
變量的值沒有錯(cuò)誤。
- 1 回答
- 0 關(guān)注
- 513 瀏覽
添加回答
舉報(bào)