为了账号安全,请及时绑定邮箱和手机立即绑定

用 Golang 和 C 编写的 Python 模块

用 Golang 和 C 编写的 Python 模块

Go
慕田峪9158850 2021-12-27 15:08:26
在 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 mainimport "fmt"// #cgo pkg-config: python3// #define Py_LIMITED_API// #include <Python.h>// int PyArg_ParseTuple_S(PyObject *,char *);import "C"//export startVMfunc 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 并导致分段错误......有人知道如何修复它吗?提前致谢。
查看完整描述

1 回答

?
哈士奇WWW

TA贡献1799条经验 获得超6个赞

零输出

这个功能:


int PyArg_ParseTuple_S(PyObject * args, char* a) {

    return PyArg_ParseTuple(args, "s", &a);

}

将只设置本地的副本a,并不会使其返回到调用函数,因为按值传递的字符串指针(复制),所以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 方法应该返回一个有效的PyObject*或NULL. 但是你的代码没有做这些。的返回值startVM没有设置,也不是默认为nil,python接受这个非nil的指针作为一个有效的对象并解引用它,这会导致分段错误。


指定返回类型startVM可能会有所帮助:


//export startVM

func startVM(self, args *C.PyObject) *C.PyObject {  

    // ...some code...

    return nil

}


查看完整回答
反对 回复 2021-12-27
  • 1 回答
  • 0 关注
  • 190 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信