【发布时间】:2018-07-20 17:57:25
【问题描述】:
我正在尝试通过 C Python API 用水晶语言编写一些 Python 函数。
我的代码如下:
METH_VARARGS = 0x0001
@[Link("python3.5m")]
lib Python
alias PyObject = Void*
struct PyMethodDef
name : UInt8*
func : Void*
flags : LibC::Int
doc : UInt8*
end
fun Py_Initialize
fun Py_Finalize
fun PyObject_CallObject(func : PyObject, args : PyObject) : PyObject
fun PyCFunction_NewEx(method : PyMethodDef*, __self__ : PyObject, ) : PyObject
fun PyLong_AsLong(n : PyObject) : Int64
fun PyLong_FromLong(n : Int64) : PyObject
end
def new_method_def(name : String, function, flags : LibC::Int)
x = Pointer(Python::PyMethodDef).malloc(1)
x.value.name = name.to_unsafe
x.value.func = function
x.value.flags = flags
x.value.doc = nil
x
end
Python.Py_Initialize
a = ->(args : Void*) {
puts Python.PyLong_AsLong(args)
Pointer(Void).null
}
name = "num"
number = Python.PyLong_FromLong(1)
Python.Py_IncRef(number)
method = Python.PyCFunction_NewEx(new_method_def(name,a.pointer,METH_VARARGS),number)
Python.PyObject_CallObject(method,Pointer(Void).null)
Python.Py_Finalize
如果我在PyCFunction_NewEx 中设置nil 而不是number,则一切正常,但正如代码所示,当调用Py_Finalize 时,它会引发无效访问内存异常。
我不明白是什么原因造成的。
有人能帮我吗?
【问题讨论】:
-
我不知道 C-API 周围的 Crystal 绑定,但
PyCFunction_NewEx采用来自PyCFunction_New的两个参数(方法对象和一个self)加上一个PyObject *module。所以,我不知道为什么这甚至可以编译,因为您将两个参数传递给三个参数的 C 函数。如果它编译,我想第三个参数很有可能最终全为 0,所以它会被读取为空模块,这会意外地起作用。但是将 int 值1作为self参数传递似乎并不正确。 -
或者Crystal可能会以某种方式在某处为您添加
self......在这种情况下,您将int1作为模块传递。显然它不是一个模块对象,如果解释器只是假设它没有检查,我可以很容易地看到段错误。 -
你能解释一下(a)这个函数应该做什么,以及(b)你试图将
PyCFunction_New的哪个参数传递给number,以及为什么你认为这是有道理的,弄清楚如何解决它可能会更容易。 -
@abarnert 这段代码只是测试这种东西是否有效。我正在创建一种嵌入式语言,我想将一些函数从这种语言传递给 python。唯一的方法是通过 PyCFuncObject 将 Crystal proc 传递给 python。我还必须将一些数据传递给这个 proc 来执行我的语言的方法,这就是为什么我试图将 int 设置为 self.但是上面的代码有效(所以你应该打印 1),当 Python 尝试释放 PyCFuncObject 的内存时,问题就出现了。
-
这是我不明白的:导致程序崩溃的无效指针在哪里?而且我很确定是在我设置自我时...
标签: python python-c-api crystal-lang