我正在尝试将字符串列表传递给C ++函数,该函数使用Cython将char **作为参数。
我尝试了其他我无法记住的解决方案,但我主要尝试了以下两个选项:
使用从here中提取的转换函数,它与here基本上是相同的答案,但它会在g++
编译
cy_wrapper.cpp: In function 'char** _pyx_f_10cy_wrapper_to_cstring_array(PyObject*)':
cy_wrapper.cpp:1223:44: error 'PyString_AsString' was not declared in this scope
__pyx_t_5 = PyString_AsString(__pyx_t_4); if (unlikely(__pyx_t_5 == ((char *)NULL))
使用python字符串的编码方法,如here中所述,但答案并不令人满意,因为它引发了错误:
cy_wrapper.pyx:14:35: Storing unsafe C derivative of temporary Python reference
我在~/.local/lib/python3.5/site-packages/Cython/Includes/cpython
查看了库文件,发现文件string.pxd
包含了我需要的函数PyString_AsString
。
为什么找不到?如果没有可能使用它,是否有解决方法?
我正在arm64 arch上使用Ubuntu 16.04.4 LTS(tegra内核)。
我的cy_wrapper.pyx
完全是这样的:
from cpython.string cimport PyString_AsString
from libc.stdlib cimport malloc
cdef extern:
cdef cppclass imageNet:
imageNet* Create(int argc, char** argv)
cdef char** to_cstring_array(list_str):
cdef char** ret = <char **>malloc(len(list_str) * sizeof(char *))
for i in range(len(list_str)):
ret[i] = PyString_AsString(list_str[i])
return ret
cdef class PyImageNet:
cdef imageNet* c_net
def Create(self, argc, kwargs):
cdef char** c_argv = to_cstring_array(kwargs)
return PyImageNetFactory(self.c_net.Create(argc, c_argv))
cdef object PyImageNetFactory(imageNet* ptr):
cdef PyImageNet py_obj = PyImageNet()
py_obj.c_net = ptr
return py_obj
我的setup.py
:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
cmdclass = {"build_ext": build_ext},
ext_modules = [
Extension("cy_wrapper",
sources=["cy_wrapper.pyx"],
libraries=["shared_inference"],
language="c++",
extra_compile_args=["-O3", "-Wall"],
extra_link_args=["-L../build/"]
)
]
)
Ofc libshared_inference.so
位于../build/
,定义了类imageNet
。
答案 0 :(得分:0)
对于那些感兴趣的人,以下是我将string
列表转换为char**
的方式(我忘记在我的问题中提到我的方法是静态的,但对于我的解决方案并不重要),希望这会对某人有所帮助。
# cy_wrapper.pyx
from libc.stdlib cimport malloc, free
cdef extern:
cdef cppclass imageNet:
@staticmethod
imageNet* Create(int argc, char** argv)
cdef class PyImageNet:
cdef imageNet* c_net
@staticmethod
def Create(args):
# Declare char**
cdef char** c_argv
# Allocate memory
c_argv = <char**>malloc(len(args) * sizeof(char*))
# Check if allocation went fine
if c_argv is NULL:
raise MemoryError()
# Convert str to char* and store it into our char**
for i in range(len(args)):
args[i] = args[i].encode()
c_argv[i] = args[i]
# Grabbing return value
cdef imageNet* c_tmp_net = imageNet.Create(len(args), c_argv)
# Let him go
free(c_argv)
# Return python-compatible value
return PyImageNetFactory(c_tmp_net)
cdef object PyImageNetFactory(imageNet* ptr):
cdef PyImageNet py_obj = PyImageNet()
py_obj.c_net = ptr
return py_obj
测试代码:
# test.py
import cy_wrapper
args = ["str1", "str2"]
net = cy_wrapper.PyImageNet.Create(args)