【问题标题】:Cython - converting list of strings to char **Cython - 将字符串列表转换为 char **
【发布时间】:2012-03-12 10:13:45
【问题描述】:

如何将 python 字符串列表转换为以 null 结尾的 char**,以便将其传递给外部 C 函数?

我有:

struct saferun_task:
    saferun_jail   *jail
    saferun_limits *limits

    char **argv
    int stdin_fd  
    int stdout_fd
    int stderr_fd

int saferun_run(saferun_inst *inst, saferun_task *task, saferun_stat *stat)

在 cdef 外部块中

我想转换像('./a.out', 'param1', 'param2') 这样的东西 我可以分配给saferun_task.argv的东西

怎么做?

【问题讨论】:

标签: arrays list cython


【解决方案1】:

来自 Cython 文档:

char* PyString_AsString (PyObject *string)

返回字符串内容的以 null 结尾的表示形式。这 指针指的是字符串的内部缓冲区,而不是副本。数据 不得以任何方式修改。它不能被取消分配。

我没有 Cython 编译器设置和方便的 atm(我可以稍后运行并检查)但是,这应该导致代码看起来像:

from libc.stdlib cimport malloc, free

cdef char **string_buf = malloc(len(pystr_list) * sizeof(char*))

for i in range(len(pystr_list)):
    string_buf[i] = PyString_AsString(pystr_list[i])

# Do stuff with string_buf as a char**
# ...

free(string_buf)

指针 stringBuf 现在是原始数据的 char **,无需复制任何字符串——尽管您不应编辑每个字符串中的数据,因为字符串应被视为 const char*(来自 docs)。如果您需要操作字符串,您将不得不 memcpy 数据或创建您不关心在 Python 中丢弃的新对象——尽管由于您有一个字符串元组,我怀疑您是否正在编辑它们。

【讨论】:

  • PyString_AsString 仅适用于 python2,因此此解决方案不适用于 python3
【解决方案2】:

Python 有权以任何非标准格式保留字符串的内部表示。因此,您必须先将字符串转换为字节,例如使用 .encode('utf-8') 或任何其他编码格式。

获得可用字节后,只需将字节分配给char * 变量,就可以轻松地将它们转换为指针,在 Cython 代码中只需执行以下操作:

s = 'abc'
b = s.encode('utf-8') + b'\x00'
cdef const char * ptr = b

请注意,在上面的代码中,我将 b'\x00' 附加到字节,因为字节表示不必在末尾包含零字节,而 C/C++ 在接受 char * 字符串时需要该零字节。

同样,如果 C/C++ 代码返回 char *,那么您可以轻松地将其转换回字符串,如下所示:

cdef const char * ptr = .... # This pointer is filled-in by C code
b = <bytes>ptr
s = s.decode('utf-8') # Now it contains string

在上面的代码中,注意从char * 到通过&lt;bytes&gt;ptr 的字节转换。 Cython 通过搜索第一个零字节并将字符串截断到它,将 char * 转换为字节,最终字节将不包含零字节。

现在您还可以创建一个 char ** 数组以将其传递给 C/C++,如下面的代码所示。我假设您正在编译 64 位二进制文​​件(使用 64 位指针):

# Imports
import numpy as np
cimport numpy as np
cimport cython
from libc.stdint cimport *

# Cython func
def cython_func():
    ss = ['ab', 'cde', 'f']
    bs = [e.encode('utf-8') + b'\x00' for e in ss]
    a = np.zeros(len(bs), dtype = np.uint64)
    for i in range(len(bs)):
        a[i] = <uint64_t>(<char *>bs[i])

    cdef uint64_t[:] ca = a
    cdef char ** final_ptr = <char **>&ca[0]

    with nogil:
        some_c_func(final_ptr)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-27
    • 2013-05-13
    • 1970-01-01
    相关资源
    最近更新 更多