1 回答

TA貢獻1863條經驗 獲得超2個贊
那個設定
所以,基本上,你得到的映射是
int* buffer
?→?buffer uintptr
int argc
→?unsafe.Pointer(&argsCount)
,其中&argsCount
是一個指向int
char* argv[]
→?unsafe.Pointer(&args)
,哪里args
是[]string
const char* fileName
→unsafe.Pointer(syscall.StringToUTF16Ptr(fileName))
const char* key
,?const char* prefix
,?const char* version
— 同上。
存在的問題
現在這有什么問題呢。
uintptr
禁止在函數之間傳遞包含活動 Go 對象地址的值。(稍后會詳細介紹。)argsCount
您將函數參數的地址傳遞給argc
。如果將其解釋為計數,則典型的商品平臺/操作系統(例如 amd64/Windows)上的地址是一個極其巨大的值。我敢打賭,當函數嘗試從中讀取這么多元素時,它會崩潰,導致
argv
它讀取進程未映射的內存。這里有兩個問題:
將切片值的地址作為參數傳遞,期望該切片的第一個元素的地址是錯誤的。
這是因為切片值(目前,在您應該使用的“參考”Go 實現中)是具有
struct
3 個字段的:底層數據數組的地址、該數組中允許使用的元素數以及總數該數組中此類元素的計數append
,在對切片值調用時,函數可以使用這些元素,而無需重新分配。當您擁有
args []string
并執行時&args
,您將獲得該結構的地址,而不是該切片的第一個元素的地址。要執行后者,請使用
&args[0]
.在 Go 中,字符串(通常是這樣,我們假設是這樣)包含編碼為 UTF-8 的字符。這通常不是 Windows 本機 C++ 代碼在表示需要
char *
.我猜,你需要首先為 構建一個合適的東西
argv
,比如argv?:=?make([]unsafe.Pointer,?0,?len(args))for?i,?s?:=?range?args?{ ????argv[i]?=?unsafe.Pointer(syscall.StringToUTF16Ptr(s)) }
然后傳遞
&argv[0]
給被調用者。但請參閱下文
syscall.StringToUTF16Ptr()
。
您正在做的將字符串數據傳遞給具有該類型的其余參數的準備工作
const char*
似乎是正確的,但前提是被調用者確實意味著它char
是一個 16 位整數。換句話說,用于編譯該庫的源代碼和工具鏈必須確保它
char
確實是wchar_t
或WCHAR
。如果是,那么你的做法應該沒問題;否則就不是。你應該驗證這一點。
uintptr
關于在表達式之間傳遞 s 的注意事項
Go 具有垃圾收集功能,因此它的運行時必須知道指向所有當前活動對象的所有指針。只要存在一個變量,其中包含指向在程序運行時分配的內存塊的指針,該塊就不會被垃圾收集。
值unsafe.Pointer
算作對內存塊的正確引用,但uintptr
值則不然。這意味著當代碼
p?:=?new(someType) u?:=?uintptr(unsafe.Pointer(&p)) foo(u)return
p
正在運行時,一旦分配了地址,GC 就可以自由地回收由 分配的對象p
,因為p
是對該對象的唯一引用,但u
事實并非如此。
現在考慮參考 Go 實現中的 GC 與程序代碼同時運行。這意味著當foo
運行時,GC 也可能會執行,并且它可能會將您的實例someType
從foo
.
作為此一般規則的一個例外,Go 編譯器保證uintptr(unsafe.Pointer)
同一語言表達式中發生的所有類型轉換都不受 GC 的影響。所以以我們之前的例子為例,這樣做就可以了
foo(uintptr(unsafe.Pointer(new(someType)))return
和
p?:=?new(someType) v?:=?unsafe.Pointer(&p) foo(uintptr(v))return
因為類型轉換發生uintptr
在單個表達式中——這是一個函數調用。
因此,您不能將指向 Go 對象的指針作為uintptr
s傳遞,除非它們包含從“C 端”獲取的指針。
- 1 回答
- 0 關注
- 188 瀏覽
添加回答
舉報