通过cython将python字符串传递给C语言

我正在尝试编写一个带有一些c和一些python部分的模块。 我正在使用cython弥补差距。

我想在python中存储我的(非常长的)字符串常量,因为它的语法更好:

const char long_string = "\npart of string\n" "next part\n" "last part\n"; 

与:

 long_string = """ part of string next part last part """ 

(字符串比这长得多,而且更复杂 – 我不想每次想要用语法高亮来编辑它时都要添加和删除" s和\n" 。事实上,它们是openCL内核。)

我需要能够使用cython将它们变成c字符串,根据文档我应该只需要:

 cdef bytes py_bytes = py_string.encode() cdef char* c_string = py_bytes 

并且没有手动内存管理,只要我保留对py_bytes的引用, c_string就会起作用。

但是,我无法通过简单的printf测试来实现这一点。 这是我的cython文件:

 cdef extern from "stdio.h": printf(char* string) def go(): py_string = """ a complicated string with a few newlines. """ cdef bytes py_bytes = py_string.encode() cdef char* c_string = py_bytes printf(c_string) print "we don't get this far :(" 

当在运行时使用pyximport编译时,在segfaulting之前向终端提供以下输出:

 a complicated string with a few newlines. Segmentation fault: 11 

现在,我已经检查了cython实际放入c文件中的内容,并在一个不会发生段错误的vanilla C文件中尝试过:

 #include "stdio.h" static char __pyx_k_1[] = "\na complicated string\nwith a few\nnewlines.\n"; int main(void) { void* output = printf(__pyx_k_1); if (!output) { printf("apparently, !output."); } } 

要清楚,cython会生成捕获printf输出的代码并测试“not that”。 变量的类型是PyObject*

我唯一的猜测是,字符串被不正确地终止,所以printf只是继续它的结尾并导致段错误,但是因为在我的纯c测试中没有发生,所以我完全被难倒了。

所以,我的实际问题是如何真正将c-string传递给cython中的c代码? 答案指出一个更容易的方法来解决我试图在顶部解决的实际问题也非常欢迎:)

libc.stdio导入printf为我解决了这个问题:

 from libc.stdio cimport printf def go(): py_string = """ a complicated string with a few newlines. """ cdef bytes py_bytes = py_string.encode() cdef char* c_string = py_bytes printf(c_string) print "we actually got this far! :)" 

错误发生在printf的声明中。 那应该是,正如stdio.pxd列出的那样,

 cdef extern from *: ctypedef char const_char "const char" int printf(const_char *, ...) 

而你的版本是隐式object printf(char *) ; 默认的返回值类型是Python对象,而不是C中的int 。获得正确的声明会关闭Cython尝试从printf返回值的Py_XDECREF

(顺便说一下,在你的“vanilla”C问题中,你不应该将printf的返回值转换为void * 。)