问题
The source code in C looks like:
typedef wchar_t char_t;
typedef const char_t* const_string_t;
static const_string_t g_symbols[] = { {L"IBM"}, {L"MSFT"}, {L"YHOO"}, {L"C"} };
...
some_c_func(g_symbols)
...
some_c_func is declared somewhere earlier with something like:
int some_c_func(const_string_t* symbols)
It is important that g_symbols is passed to some_c_func function, so I have to write wrapper over it, that should look somehow like:
ctypedef wchar_t char_t
ctypedef const char_t* const_string_t
def some_py_func(py_list=['a', 'b', 'c']):
g_symbols = ... # some transformation from py_list to g_symbols
some_c_func(g_symbols)
print('Done!')
I will appreciate any help
回答1:
The easiest way to get a wchar*
from a unicode object is probably PyUnicode_AsWideCharString. Cython doesn't provide a definition so you need to do a suitable cdef extern
yourself:
from libc.stddef cimport wchar_t
from cpython.mem cimport PyMem_Free
cdef extern from "Python.h":
wchat_t* PyUnicode_AsWideCharString(object, Py_ssize_t*) except NULL
def f(string):
cdef wchar_t* c_string = PyUnicode_AsWideCharString(string, NULL)
# use the string
PyMem_Free(<void*>c_string) # you must free it after use
Read the documentation to see if you should use the "size" argument.
To allocate space for an array of wchar_t*
you should use malloc
or calloc
. You should free
this space when you're done with it. You need to cast from malloc
from libc.stdlib cimport malloc, free
cdef wchar_t** strings = <wchar_t**>malloc(sizeof(wchar_t*)*length)
# do something
free(<void*>strings)
A common pattern from ensuring memory is cleaned up to use try and finally:
def some_py_func(py_list):
g_symbols = malloc(...)
try:
# loop through py_list getting wchar_t*
# call your C function
finally:
# loop through g_symbols calling PyMem_Free
free(g_symbols)
You need to be careful that you only call PyMem_Free
on valid (or NULL
) pointers in the event of an exception. Remember that memory from malloc
may be filled with arbitrary values that it isn't safe to pass to PyMem_Free
.
回答2:
Thanks to @DavidW, but I found, I think, simplier solution:
from cpython.mem cimport PyMem_Malloc, PyMem_Free
def some_py_func(py_list=['a', 'b', 'c']):
cdef int number = len(symbols) # get c int of elements
cdef int idx # for faster loops
# create array with dynamic memory allocation
cdef const_string_t *g_symbols = <const_string_t *> PyMem_Malloc(number * sizeof(const_string_t))
# create array with cycle
for idx, sym in enumerate(py_list):
g_symbols[idx] = PyUnicode_AsWideCharString(sym, NULL)
# call c function
some_c_func(g_symbols)
# free memory
for idx in range(number):
PyMem_Free(g_symbols[idx])
PyMem_Free(g_symbols)
print('Done!')
来源:https://stackoverflow.com/questions/56185968/how-to-convert-python-list-of-strings-into-c-array-of-wchar-t