Как преобразовать список строк Python в массив C из wchar_t? - PullRequest
0 голосов
/ 17 мая 2019

Исходный код на C выглядит следующим образом:

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 объявлен где-то ранее с чем-то вроде:

int some_c_func(const_string_t* symbols)

Важно, что g_symbols передается в функцию some_c_func, поэтомуНадо написать над ним обертку, которая должна выглядеть примерно так:

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!')

Я буду признателен за любую помощь

Ответы [ 2 ]

1 голос
/ 21 мая 2019

Самый простой способ получить wchar* от объекта Unicode - это, вероятно, PyUnicode_AsWideCharString.Cython не предоставляет определения, поэтому вам нужно сделать подходящее cdef extern самостоятельно:

 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

Прочтите документацию, чтобы узнать, следует ли использовать аргумент "size".

Длявыделить место для массива wchar_t*, вы должны использовать malloc или calloc.Вы должны free это место, когда вы закончите с этим.Вам нужно привести из malloc

from libc.stdlib cimport malloc, free

cdef wchar_t** strings = <wchar_t**>malloc(sizeof(wchar_t*)*length)
# do something
free(<void*>strings)

Обычный шаблон из проверки очистки памяти для использования try и 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)

Вам нужно быть осторожным, чтобы вы только вызывалиPyMem_Free на действительные (или NULL) указатели в случае исключения.Помните, что память из malloc может быть заполнена произвольными значениями, которые небезопасно передавать в PyMem_Free.

0 голосов
/ 21 мая 2019

Благодаря @DavidW, но я нашел, я думаю, более простое решение:

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!')
...