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 考慮并且表現得像包含地址的“正?!敝怠缟纤觥?/p>通過將此類值類型轉換為
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 關注
- 537 瀏覽
添加回答
舉報