通过Python字符串,通过用Cython,到C [英] passing python strings, through cython, to C

查看:825
本文介绍了通过Python字符串,通过用Cython,到C的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想写一些C和一些Python部分的模块。我使用用Cython来弥补缺口。

我想我的(很长)字符串常量存储,因为好多了语法的蟒蛇,

为const char long_string =字符串的\\ n \\ npart
  下一部分\\ n
  最后一部分\\ n;

long_string =
串的一部分
下一部分
最后一部分

(字符串比这长得多,而且更为复杂 - 来,我不希望有添加和删除和程度 \\ n s中每个时间我想与语法高亮编辑它。事实上,他们是OpenCL内核。)

我需要能够通过用Cython把这些放到C字符串,并根据的文档我只是需要这样的:

字节CDEF = py_bytes py_string.en code()
CDEF的char * C_STRING = py_bytes

和不带手动内存管理, C_STRING 将只要我保持 py_bytes 。<参考工作/ p>

不过,我不能得到这个工作,用一个简单的printf测试。这是我用Cython文件:

从stdio.h中 CDEF EXTERN:
  的printf(字符*字符串)DEF去():
  py_string =
一个复杂的字符串
有几
换行。
  CDEF字节py_bytes = py_string.en code()  CDEF的char * C_STRING = py_bytes  的printf(C_STRING)  打印:我们不走这么远:(

,当在运行时使用 pyximport 编译给出以下输出端子之前段错误:

 一个复杂的字符串
有几
换行。
段故障:11

现在,我已经查了一下用Cython在C文件其实是把,并试图在一个香草的C文件它的段错误:

的#includestdio.h中静态CHAR __pyx_k_1 [] =\\呐n执行数\\ nnewlines复杂的字符串\\ \\ n;诠释主要(无效){
  void *的输出=的printf(__ pyx_k_1);
  如果(!输出){
    输出(!显然,输出);
  }
}

要清楚,用Cython产生code惹人的输出的printf 和试验不是。变量的类型是的PyObject *

我只能猜测这里是字符串不当终止,所以printf的只是进行过去它的结束,并导致段错误,但因为这并不在我的纯C测试发生了,我完全难住了。

所以,我的实际问题是我怎么确实的距离用Cython传递一个C字符串到c code?指出了一个更简单的方式回答解决我想在上面解决也非常欢迎的实际问题:)


解决方案

导入的printf libc.stdio 修复对我来说问题:

 从libc.stdio cimport的printfDEF去():
    py_string =
一个复杂的字符串
有几
换行。
    CDEF字节py_bytes = py_string.en code()
    CDEF的char * C_STRING = py_bytes
    的printf(C_STRING)    打印事实上,我们走到这一步!:)

该错误是在的printf 的声明。本来应该,因为 stdio.pxd 名单,

  CDEF的extern从*:
    ctypedef字符const_char为const charINT的printf(const_char *,...)

而你的版本是隐含对象的printf(字符*);默认返回值类型是Python的对象,而不是 INT 为C.获得正确的声明关闭用Cython的尝试 Py_XDECREF 的返回值的printf

(顺便说一下,在你的香草C的问题,你不应该从的printf 的返回值转换为无效*

I am trying to write a module with some c and some python parts. I am using cython to bridge the gap.

I want to store my (very long) string constants in python, because of the much nicer syntax:

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

versus:

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

(the strings are much longer than this, and more complicated - to the extent that I don't want to have to add and remove the "s and \n"s every time I want to edit it with syntax highlighting. In fact, they are openCL kernels.)

I need to be able to turn these into c strings using cython, and according to the documentation I should just need this:

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

and with no manual memory management, c_string will work as long as I keep a reference to py_bytes.

However, I can't get this working with a simple printf test. Here is my cython file:

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 :("

which, when compiled at runtime using pyximport gives the following output to terminal before segfaulting:

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

now, I've checked what cython actually puts in the c file, and tried it in a vanilla C file where it doesn't segfault:

#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.");
  }
}

to be clear, cython generates code which catches the output of printf and tests for "not that". the type of the variable is a PyObject*.

My only guess here was that the string was improperly terminated, so printf just carries on past the end of it and causes the segfault, but since that doesn't happen in my pure c test, I'm completely stumped.

So, my actual question is how do I really pass a c-string to c code from cython? Answers pointing out an easier way to solve the actual problem I'm trying to solve at the top are also very welcome :)

解决方案

Importing printf from libc.stdio fixes the problem for me:

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! :)"

The error is in the declaration of printf. That should have been, as stdio.pxd lists,

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

int printf(const_char *, ...)

whereas your version is implicitly object printf(char *); the default return value type is Python object rather than int as in C. Getting the right declaration turns off Cython's attempt to Py_XDECREF the return value from printf.

(Btw, in your "vanilla" C problem, you shouldn't be casting the return value from printf to void *.)

这篇关于通过Python字符串,通过用Cython,到C的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆