亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

將包含 *byte 的結構傳遞給 Syscall 并在執行后讀取其內容

將包含 *byte 的結構傳遞給 Syscall 并在執行后讀取其內容

Go
守候你守候我 2023-07-31 16:23:43
我用來syscall.Syscall(...)調用 dll 中的 C 方法。這是 C 方法簽名:SENSEI_API HSENSEI SENSEI_open(const char* sensigrafo, const char* options, SENSEI_ERR* se);這是SENSEI_ERR結構:typedef struct{    int code;    char* error_string;} SENSEI_ERR;在我的 GO 程序中,我聲明了一個結構:type senseiErr struct {    code         int    error_string *byte}并嘗試調用該方法:    var nargs uintptr = 3    var err senseiErr    ret, _, callErr := syscall.Syscall(uintptr(senseiOpen),        nargs,        uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("en"))),        uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(""))),        uintptr(unsafe.Pointer(&err)),    )正如您可能已經猜到的,該方法用錯誤的代碼和文本SENSEI_open填充參數。SENSEI_ERR現在我需要閱讀該錯誤的內容。err.code實際上有正確的值。關于err.error_string我不知道。我是 GO 新手,有一些問題:由于 C 結構體有字段char* error_string,error_string *byte我的 GO 結構體是否正確?我應該使用[]byte還是其他東西?如何讀取該error_string字段的內容?fmt.Println(err.error_string)打印內存地址fmt.Println(*err.error_string)始終打印“101”
查看完整描述

1 回答

?
倚天杖

TA貢獻1828條經驗 獲得超3個贊

1)我懷疑這cost char*是否意味著UTF16編碼。所以你所需要的只是獲取原始數據:


sensigrafo := "en\000" // \000 = 0 = null termination, \0 does not valid

options := "\000"


...


uintptr(*(*unsafe.Pointer)(unsafe.Pointer(&sensigrafo))

uintptr(*(*unsafe.Pointer)(unsafe.Pointer(&options))


// *(*unsafe.Pointer) are accessing the first field of string header:

type string struct {

    data *byte

    len int

}


// same with slices

// but for them there's less ugly way:

sensigrafo := []byte("en\000")

options := []byte("\000")


uintptr(unsafe.Pointer(&sensigrafo[0]))

uintptr(unsafe.Pointer(&options[0]))

2) Cint和 Golangint可能有不同的 sizeof,所以這需要 cgo 聲明 ( C.int) 或手動匹配隨機選擇(如果你不想使用 cgo,也可以嘗試 int32、int64)


type senseiErr struct {

    code         C.int /* Golang's int32/int64 */

    error_string *byte // pointer types are same as C's void* or Golang's unsafe.Pointer

}

錯誤的偏移量可能會導致 error_string 為空或指向隨機地址。


3)要讀取內容,您必須使用與 C 相同的方法(讀取數據直到 null 終止字節,考慮到 *byte 指向字符串的第一個元素),但我建議使用已經實現的運行時函數:


//go:linkname gostringn runtime.gostringn

func gostringn(p *byte, l int) string


//go:linkname findnull runtime.findnull

//go:nosplit

func findnull(s *byte) int


...


error_string := gostringn(err.error_string, findnull(err.error_string))


// or cgo one:


type senseiErr struct {

    code         C.int

    error_string *C.char

}


...


error_string := C.GoString(err.error_string)


查看完整回答
反對 回復 2023-07-31
  • 1 回答
  • 0 關注
  • 138 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號