首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在Crystal-lang中编写Python函数时出错

在Crystal-lang中编写Python函数时出错
EN

Stack Overflow用户
提问于 2018-07-21 01:57:25
回答 1查看 159关注 0票数 4

我正在尝试通过C python API用crystal-lang编写一些Python函数。

我的代码如下:

代码语言:javascript
复制
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时,它会抛出一个无效的访问内存异常。我不明白是什么引起的。有人能帮我吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-07-21 05:24:07

这里的根本问题是,您调用的C函数有三个参数,但只有两个参数。

遗憾的是,PyCFunction_NewEx is missing from the documentation, despite being a public API function.使用它的所有示例都传递了三个参数。如果你去the source

代码语言:javascript
复制
PyObject *
PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)

这是3.7版本,但这是相同的in 3.5in 2.7,并且在函数被添加到in 2.3接口之后的所有其他版本中都是如此。NewEx的全部意义在于允许您传递一个模块。

假设函数需要第三个参数,或者在寄存器中,或者在堆栈中,而您没有将任何内容放在那里,所以传递的内容完全是任意的。稍微不同的代码将在这些地方留下完全不同的值,所以得到不同的结果也就不足为奇了:

  • 如果值恰好是0,这很好;您可以将NULL作为代码值传递。module
  • 如果此值恰好是指向未映射内存的值,例如,1 (就像在原始C incref / long long中那样,而不是1),那么您应该从尝试incref模块时获得段错误。

<1>h116如果此值恰好是指向内存中某个随机对象的指针,则增量将起作用,但会破坏该随机对象。这几乎可以做任何事情,但在稍后的某个任意时刻出现神秘的段错误几乎是它所能做的最不令人惊讶的事情。

与此同时,来自一条评论:

我之所以调用PyCFunction_NewEx,是因为PyCFunction_New在源代码中是一个

如果您使用的是Python 2.3-2.6或3.0-3.2,那么当然可以。但是在以后的版本中,包括你说你正在使用的3.5版本,CPython会特意将PyCFunction_New定义为一个函数,这样它就会出现在API中(甚至是3.x的稳定API )。例如,请参阅3.5

代码语言:javascript
复制
/* undefine macro trampoline to PyCFunction_NewEx */
#undef PyCFunction_New

PyAPI_FUNC(PyObject *)
PyCFunction_New(PyMethodDef *ml, PyObject *self)
{
    return PyCFunction_NewEx(ml, self, NULL);
}

所以,你真的可以直接调用PyCFunction_New

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51448030

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档