I am trying to understand how to pass string values between Python3 and cythonized C++ function. However I am unable to build the library with Cython.
In particular, I didn't understand how to declare the string return value and string parameter in the source.pyx
. With the int type it works correctly.
The error I get during build with clang is the following:
candidate function not viable: no known conversion from 'PyObject *' (aka '_object *') to 'char *' for 1st argument
My source.pyx
is the following:
cdef extern from "source.cpp":
cdef str fun(str param)
def pyfun(mystring):
return fun(mystring)
My source.cpp
is:
char * fun(char *string) {
return string;
}
Aside from mistakes in the original code, I managed to make it work with the following source.pyx
(translation between bytes
type in Python3 and char*
in C++):
cdef extern from "source.cpp":
cdef char* fun(char* param)
def pyfun(mystring):
mystring_b = mystring.encode('utf-8')
rvalue = fun(mystring_b).decode('utf-8')
return rvalue
If the memory is allocated using malloc
within fun
it will also need to be freed, otherwise there will be a memory leak (when working with C pointers it's always worth considering who owns the memory). A modified version that does this is:
from libc.stdlib cimport free
# cdef extern as before
def pyfun(mystring):
cdef char* value_from_fun
mystring_b = mystring.encode('utf-8')
value_from_fun = fun(mystring_b)
try:
return value_from_fun.decode('utf-8')
finally:
free(value_from_fun)
The type conversions act in the same way as before.
As per hpaulj's comment in the original question, here is the version with libcpp.string
which maps C++ std::string
defined in <string>
:
from libcpp.string cimport string
cdef extern from "source.cpp":
cdef string fun(string param)
def pyfun(mystring):
mystring_ = mystring.encode('utf-8')
rvalue = fun(mystring_).decode('utf-8')
return rvalue