【问题标题】:How to create a valid CFFI representation of a numpy array of unicode strings?如何创建一个 numpy unicode 字符串数组的有效 CFFI 表示?
【发布时间】:2021-12-23 16:25:54
【问题描述】:

我有一个名为valuesnumpy.ndarray 包含numpy.unicode_ 字符串,并且我有一个C 函数foo,它使用一个C 字符串数组。 foo 有一个 CFFI 封装接口。

所以我试着做这样的事情

p = ffi.from_buffer("char**", values)

还有

p = ffi.from_buffer("char*[]", values)

这不会在 CFFI 中给出任何错误。但是,一旦我运行代码,它就会在 foo 的 C 实现中崩溃,实际上,当我查看指针时,它们看起来很糟糕:

(gdb) p d
$1 = (char **) 0x1f978a50
(gdb) p d[0]
$2 = 0x7300000061 <error: Cannot access memory at address 0x7300000061>

我使用的是 64 位架构。

【问题讨论】:

    标签: python python-cffi


    【解决方案1】:

    我相信它不会像您尝试做的那样工作,因为 numpy 数组包含指向 Python 对象的指针(所有类型为 str)。在任何情况下,它都不是 char * 指向字符串的 UTF8 编码版本的原始数组。

    我认为没有自动的方法来进行转换。您需要手动对项目进行循环,并将所有字符串手动转换为char[] 数组,并确保它们都保持足够长的时间。应该这样做:

    items = [ffi.new("char[]", x.encode('utf-8')) for x in values]
    p = ffi.new("char *[]", items)
    # keep 'items' alive as long as you need 'p'
    

    或者,如果您只需要调用一个需要 char ** 参数的 C 函数,那么您可以依赖 Python 列表到 C 数组的自动转换,只要 Python 列表的每个项目都是char *:

    items = [ffi.new("char[]", x.encode('utf-8')) for x in values]
    lib.my_c_function(items)
    

    【讨论】:

      【解决方案2】:

      问题在于numpy 并没有真正将C 字符串数组表示为char*[]。但它更像是一个大的单个char[],其中所有字符串都使用等于.itemsize 的步幅出现,在字符串数组的情况下是最大出现字符串的大小。较短的字符串用零字节填充。并且ffi.from_buffer 中可选的第一个参数cdecl 不涉及对接收到的底层缓冲区/内存视图进行任何严格的类型检查。程序员有责任知道感知到的缓冲区/内存视图的正确类型。

      cdecl 参数在与调用其他 CFFI 包装函数结合使用时将提供类型安全。

      我解决这个问题的方法是在 cffi 中分配一个单独的 char 指针数组

      t = ffi.new('char*[]', array_size)
      

      接下来稍微调整一下 numpy 数组,以确保每个字符串都以空值结尾。 然后在 Python 中实现一些逻辑(或 C,如果需要性能,然后包装在 CFFI 中) 将 char*[] 数组中的每个成员指向 numpy 数组中对应的字符串。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多