将包含 *byte 的结构传递给 Syscall 并在执行后读取其内容

我用来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_stringerror_string *byte我的 GO 结构体是否正确?

    • 我应该使用[]byte还是其他东西?

  • 如何读取该error_string字段的内容?

    • fmt.Println(err.error_string)打印内存地址

    • fmt.Println(*err.error_string)始终打印“101”


守候你守候我
浏览 74回答 1
1回答

倚天杖

1)我怀疑这cost char*是否意味着UTF16编码。所以你所需要的只是获取原始数据:sensigrafo := "en\000" // \000 = 0 = null termination, \0 does not validoptions := "\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.gostringnfunc gostringn(p *byte, l int) string//go:linkname findnull runtime.findnull//go:nosplitfunc 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)
打开App,查看更多内容
随时随地看视频慕课网APP