Passing python strings, through cython, in C

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

I want to keep my (very long) string constants in python due to a much nicer syntax:

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

vs

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

(The lines are much longer and harder - until I want to add and remove " and \n" every time I want to edit it with syntax highlighting. In fact, they are openCL kernels.)

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

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

and without manual memory management, c_string will work as long as I keep the link to py_bytes .

However, I cannot get this to work 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 the terminal before segfault:

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

Now, I checked that cython actually places the file in c, and tried it in the C vanilla file, where there is no 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 that catches printf output and checks for the "wrong". the type of the variable is PyObject* .

My only assumption was that the line was improperly terminated, so printf just continues to the end and calls segfault, but since this does not happen in my pure c-test, I am completely at a dead end.

So my actual question is: how can I pass a c-string to cython c-code? Answers pointing to a simpler way to solve the actual problem that I am trying to solve at the top are also very welcome :)

+4
source share
1 answer

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

Error in printf declaration. It should be like 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 type is a Python object, not an int , as in C. Getting the correct declaration disables Cython trying Py_XDECREF to return the value from printf .

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

+7
source

Source: https://habr.com/ru/post/1382317/


All Articles