简体   繁体   English

如何将Python字符串列表转换为wchar_t的C数组?

[英]How to convert Python list of strings into C array of wchar_t?

The source code in C looks like: 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 is declared somewhere earlier with something like: some_c_func之前在某处声明了类似于:

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: 重要的是将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!')

I will appreciate any help 我将不胜感激任何帮助

The easiest way to get a wchar* from a unicode object is probably PyUnicode_AsWideCharString . 从unicode对象获取wchar*的最简单方法可能是PyUnicode_AsWideCharString Cython doesn't provide a definition so you need to do a suitable cdef extern yourself: 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

Read the documentation to see if you should use the "size" argument. 阅读文档,看看是否应该使用“size”参数。

To allocate space for an array of wchar_t* you should use malloc or calloc . 要为wchar_t*数组分配空间,您应该使用malloccalloc You should free this space when you're done with it. 完成后你应该free这个空间。 You need to cast from malloc 你需要从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: 确保内存清除的常见模式使用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)

You need to be careful that you only call PyMem_Free on valid (or NULL ) pointers in the event of an exception. 您需要注意,只有在发生异常时PyMem_Free在有效(或NULL )指针上调用PyMem_Free Remember that memory from malloc may be filled with arbitrary values that it isn't safe to pass to PyMem_Free . 请记住, malloc可能会填充任意值,传递给PyMem_Free

Thanks to @DavidW, but I found, I think, simplier solution: 感谢@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!')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM