Python 用 Golang 和 C 编写的模块
Python module written in Golang and C
我关注这个tutorial
在 C:
中编写此代码
#define Py_LIMITED_API
#include <Python.h>
PyObject * startVM(PyObject *, PyObject *);
int PyArg_ParseTuple_S(PyObject * args, char* a) {
return PyArg_ParseTuple(args, "s", &a);
}
static PyMethodDef FooMethods[] = {
{"startVM", startVM, METH_VARARGS, "Starts."},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef foomodule = {
PyModuleDef_HEAD_INIT, "foo", NULL, -1, FooMethods
};
PyMODINIT_FUNC PyInit_foo(void) {
return PyModule_Create(&foomodule);
}
GO 中的这段代码:
package main
import "fmt"
// #cgo pkg-config: python3
// #define Py_LIMITED_API
// #include <Python.h>
// int PyArg_ParseTuple_S(PyObject *,char *);
import "C"
//export startVM
func startVM(self, args *C.PyObject) {
var a *C.char
if C.PyArg_ParseTuple_S(args, a) == 0 {
//return nil
}
fmt.Println(a)
//return C.PyBytes_FromString(&a)
}
func main() {}
我可以在 go 中编译代码,但是当我使用此命令调用 python 模块时:python3 -c 'import foo; foo.startVM("hello")'
,它打印 nil 并导致分段错误...
有人知道如何解决吗?
提前致谢。
无输出
这个函数:
int PyArg_ParseTuple_S(PyObject * args, char* a) {
return PyArg_ParseTuple(args, "s", &a);
}
只会设置 a
的 local 副本并且 不会 return 它进入调用函数,因为您按值(通过复制)传递字符串指针,所以 PyArg_ParseTuple
仅设置副本。
var a *C.char
C.PyArg_ParseTuple_S(args, a)
// Here `a` is not set, so it keeps its default value: nil.
您可以通过将指针传递给字符串而不是字符串本身来解决此问题:
// C
int PyArg_ParseTuple_S(PyObject * args, char** a) {
return PyArg_ParseTuple(args, "s", a);
}
// Go
var a *C.char
if C.PyArg_ParseTuple_S(args, &a) == 0 {
//return nil
}
正确打印
fmt.Println(a)
将打印 a
持有的地址,而不是它指向的字符串。 Go 有自己的字符串类型,不适用于 C 字符串。
如果要正确打印文本,必须使用 C.GoString
:
进行转换
// C string to Go string
func C.GoString(*C.char) string
(来自 https://golang.org/cmd/cgo/)
例如:
str := C.GoString(a)
fmt.Println(str)
分段错误。
我不熟悉 python 模块开发,但我可以假设,故障发生了,因为 python 方法需要 return 一个有效的 PyObject*
或 NULL
。但是您的代码确实 none 了。 startVM
的 return 值未设置且不默认为 nil,python 接受此非 nil 指针作为有效对象并取消引用它,这会导致分段错误。
指定 startVM
的 return 类型可能有帮助:
//export startVM
func startVM(self, args *C.PyObject) *C.PyObject {
// ...some code...
return nil
}
我关注这个tutorial
在 C:
中编写此代码#define Py_LIMITED_API
#include <Python.h>
PyObject * startVM(PyObject *, PyObject *);
int PyArg_ParseTuple_S(PyObject * args, char* a) {
return PyArg_ParseTuple(args, "s", &a);
}
static PyMethodDef FooMethods[] = {
{"startVM", startVM, METH_VARARGS, "Starts."},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef foomodule = {
PyModuleDef_HEAD_INIT, "foo", NULL, -1, FooMethods
};
PyMODINIT_FUNC PyInit_foo(void) {
return PyModule_Create(&foomodule);
}
GO 中的这段代码:
package main
import "fmt"
// #cgo pkg-config: python3
// #define Py_LIMITED_API
// #include <Python.h>
// int PyArg_ParseTuple_S(PyObject *,char *);
import "C"
//export startVM
func startVM(self, args *C.PyObject) {
var a *C.char
if C.PyArg_ParseTuple_S(args, a) == 0 {
//return nil
}
fmt.Println(a)
//return C.PyBytes_FromString(&a)
}
func main() {}
我可以在 go 中编译代码,但是当我使用此命令调用 python 模块时:python3 -c 'import foo; foo.startVM("hello")'
,它打印 nil 并导致分段错误...
有人知道如何解决吗?
提前致谢。
无输出
这个函数:
int PyArg_ParseTuple_S(PyObject * args, char* a) {
return PyArg_ParseTuple(args, "s", &a);
}
只会设置 a
的 local 副本并且 不会 return 它进入调用函数,因为您按值(通过复制)传递字符串指针,所以 PyArg_ParseTuple
仅设置副本。
var a *C.char
C.PyArg_ParseTuple_S(args, a)
// Here `a` is not set, so it keeps its default value: nil.
您可以通过将指针传递给字符串而不是字符串本身来解决此问题:
// C
int PyArg_ParseTuple_S(PyObject * args, char** a) {
return PyArg_ParseTuple(args, "s", a);
}
// Go
var a *C.char
if C.PyArg_ParseTuple_S(args, &a) == 0 {
//return nil
}
正确打印
fmt.Println(a)
将打印 a
持有的地址,而不是它指向的字符串。 Go 有自己的字符串类型,不适用于 C 字符串。
如果要正确打印文本,必须使用 C.GoString
:
// C string to Go string
func C.GoString(*C.char) string
(来自 https://golang.org/cmd/cgo/)
例如:
str := C.GoString(a)
fmt.Println(str)
分段错误。
我不熟悉 python 模块开发,但我可以假设,故障发生了,因为 python 方法需要 return 一个有效的 PyObject*
或 NULL
。但是您的代码确实 none 了。 startVM
的 return 值未设置且不默认为 nil,python 接受此非 nil 指针作为有效对象并取消引用它,这会导致分段错误。
指定 startVM
的 return 类型可能有帮助:
//export startVM
func startVM(self, args *C.PyObject) *C.PyObject {
// ...some code...
return nil
}