英文:
How to access multiple return values in restype?
问题
我正在编写一个类似下面的 Go 程序:
package main
import (
"C"
)
//export getData
func getData(symbol string, day string, month string, year string) (string, string) {
return "A", "B"
}
func main() {
}
在 Python 中,我正在进行以下操作:
import ctypes
library = ctypes.cdll.LoadLibrary('./deribit.so')
get_data = library.getData
# 让 Python 将其值转换为 C 表示形式。
get_data.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_wchar_p]
get_data.restype = ctypes.POINTER(ctypes.c_wchar), ctypes.POINTER(ctypes.c_wchar)
d, c = get_data("symbol", "day", "month", "year")
print(d, c)
但是它报错了:
get_data.restype = ctypes.c_wchar, ctypes.c_wchar
TypeError: restype must be a type, a callable, or None
英文:
I am writing a Go program like the below:
package main
import (
"C"
)
//export getData
func getData(symbol string, day string, month string, year string) (string, string) {
return "A", "B"
}
func main() {
}
In Python, I am doing this:
import ctypes
library = ctypes.cdll.LoadLibrary('./deribit.so')
get_data = library.getData
# Make python convert its values to C representation.
get_data.argtypes = [ctypes.c_wchar, ctypes.c_wchar,ctypes.c_wchar,ctypes.c_wchar]
get_data.restype = [ctypes.c_wchar,ctypes.c_wchar]
d,c = get_data("symbol", "day","month","year")
print(d,c)
And it gives the error:
get_data.restype = ctypes.c_wchar,ctypes.c_wchar
TypeError: restype must be a type, a callable, or None
答案1
得分: 3
从cgo文档中可以得知:
Go函数可以通过以下方式导出供C代码使用:
//export MyFunction
func MyFunction(arg1, arg2 int, arg3 string) int64 {...}
//export MyFunction2
func MyFunction2(arg1, arg2 int, arg3 string) (int64, *C.char) {...}
在C代码中,它们将以如下方式可用:
extern GoInt64 MyFunction(int arg1, int arg2, GoString arg3);
extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);
这些声明可以在生成的头文件_cgo_export.h
中找到,位于从cgo输入文件复制的任何前导之后。具有多个返回值的函数将映射为返回结构体的函数。
返回多个值的函数将映射为返回结构体的函数。请查看生成的_cgo_export.h
头文件以查看结构体定义;文档对结构体定义的形式没有明确说明。我猜测它只是按照函数返回值的顺序包含所有返回值,并带有一些未指定的自动生成的名称,但文档没有说明。
(上述代码中的GoString
可能应该是_GoString_
;这是链接的文档页面中唯一一个没有下划线的GoString
。这可能是一个错误。)
然而,你还有其他问题,这两个问题都将阻止你调用getData
函数。
第一个问题是Go字符串不是char *
类型,它是一种独立的类型。C代码可以通过_GoString_
类型和几个辅助函数与Go字符串进行交互,但是从外部创建Go字符串是不支持的。
第二个问题是由于Go的垃圾回收机制,非Go代码与指向Go内存的指针交互有很多限制。其中一个限制是Go代码不能将Go字符串返回给非Go代码,也不能返回包含指向Go内存的指针的任何其他内容。你的getData
函数返回Go字符串,因此无法从Go外部调用。
英文:
From the cgo docs:
> Go functions can be exported for use by C code in the following way:
>
> //export MyFunction
> func MyFunction(arg1, arg2 int, arg3 string) int64 {...}
>
> //export MyFunction2
> func MyFunction2(arg1, arg2 int, arg3 string) (int64, *C.char) {...}
>
> They will be available in the C code as:
>
> extern GoInt64 MyFunction(int arg1, int arg2, GoString arg3);
> extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);
>
> found in the _cgo_export.h generated header, after any preambles
> copied from the cgo input files. Functions with multiple return values
> are mapped to functions returning a struct.
A function that returns multiple values gets mapped to a function returning a struct. Read the _cgo_export.h
generated header to see the struct definition; the documentation is unclear on what the struct definition looks like. I would guess it just contains all return values in the order the function returns them, with some unspecified auto-generated names, but the documentation doesn't say.
(GoString
in the above code should probably say _GoString_
; this is the only part of the linked documentation page that writes GoString
without underscores. It's probably an error.)
However, you have other problems, both of which will prevent you from calling your getData
function.
The first problem is that a Go string is not a char *
. It is its own separate type. C code can interact with Go strings through the _GoString_
type and several helper functions, but creating Go strings from outside Go is unsupported.
The second is that due to Go garbage collection, there are many restrictions on how non-Go code is allowed to interact with pointers to Go memory. One of the restrictions is that Go code cannot return Go strings to non-Go code, or return anything else that contains pointers to Go memory. Your getData
returns Go strings, so it cannot be called from outside Go.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论