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

teh*_*rus 5 c python cython

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

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

const char long_string = "\npart of string\n"
  "next part\n"
  "last part\n";
Run Code Online (Sandbox Code Playgroud)

与:

long_string = """
part of string
next part
last part
"""
Run Code Online (Sandbox Code Playgroud)

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

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

cdef bytes py_bytes = py_string.encode()
cdef char* c_string = py_bytes
Run Code Online (Sandbox Code Playgroud)

并且没有手动内存管理,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 :("
Run Code Online (Sandbox Code Playgroud)

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

a complicated string
with a few
newlines.
Segmentation fault: 11
Run Code Online (Sandbox Code Playgroud)

现在,我已经检查了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.");
  }
}
Run Code Online (Sandbox Code Playgroud)

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

我唯一的猜测是,字符串被不正确地终止,所以printf只是继续它的结束并导致段错误,但由于这不会发生在我的纯c测试中,我完全被难倒了.

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

Fre*_*Foo 8

导入printflibc.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! :)"
Run Code Online (Sandbox Code Playgroud)

错误在声明中printf.那应该是,作为stdio.pxd名单,

cdef extern from *:
    ctypedef char const_char "const char"

int printf(const_char *, ...)
Run Code Online (Sandbox Code Playgroud)

而你的版本含蓄object printf(char *); 默认的返回值类型是Python对象而不是intC中.获得正确的声明会关闭Cython尝试Py_XDECREF返回值printf.

(顺便说一下,在你的"vanilla"C问题中,你不应该将返回值转换printfvoid *.)