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

时间:2011-11-21 16:42:22

标签: python c cython

我正在尝试用一些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
"""

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

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

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

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

但是,我无法使用简单的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的输出并测试“不是那个”。变量的类型是PyObject*

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

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

1 个答案:

答案 0 :(得分:8)

printf导入libc.stdio可以解决我的问题:

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尝试从Py_XDECREF printf返回值。

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