问题
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