【问题标题】:Pass string as a c_ubyte array to C将字符串作为 c_ubyte 数组传递给 C
【发布时间】:2020-11-12 19:37:33
【问题描述】:

C 中,我有一个函数需要unsigned chars 的数组

void writedata(unsigned char *datapos, int datanum)

我想从 Python 传递一个标准字符串

writedata = parallel.writedata
writedata.argtypes = [POINTER(c_ubyte), c_int]

a = "test string"
writedata(a, 11)

据我了解,字符串实际上是一个字节/字符数组,a 是一个指针。但是,ctypes 不同意:

ctypes.ArgumentError: argument 2: <type 'exceptions.TypeError'>: expected LP_c_ubyte instance instead of str

如何从字符串中获取“真实”指针?

编辑:David Cullen 提供了一个以字符串指针为参数的解决方案:

writedata.argtypes = [c_char_p, c_int]

这很好,但我想为函数提供 byte arrays 和 strings。这意味着这也应该有效

ll = [0,1,2,3,4,5,6,7]
uints = (c_ubyte*8)(*ll)
writedata(uints, 8)

我很好奇为什么我不能两者都做,因为在内存方面我认为字节数组和字符串应该是一样的?也许这都是关于指针转换的?

我还尝试将两个ctypes 连接到同一个C 函数,但这不起作用。

解决方案:我重新提出了问题并在此处获得了最佳答案:

https://stackoverflow.com/a/64838842/2957687

【问题讨论】:

  • 我想你可能会发现这个问题很有用:click me
  • @IkarusDeveloper 必须是ctypes。我已经编写了一个巨大的程序,所有其他 Python C 通信由 ctypes 完成
  • “据我所知,字符串实际上是一个字节/字符数组” - C 字符串是,但不是 Python 字符串。 Python 字符串是 Unicode 代码点的抽象序列,它可能有多种不同的内存表示。
  • @user2357112supports Monica Fair 论点。如果我知道只有 ASCII 字符,或者如果我把b 放在前面,即b"test string",该怎么办?
  • @Pygmalion:将b 放在前面使其成为bytes,而不是str,所以它应该可以工作。

标签: python c ctypes


【解决方案1】:

如果我们转换字符串以匹配所需的参数类型,我们可以使用相同的函数:

def writedata(value):
    if isinstance(value, str):
        value = (ctypes.c_ubyte * len(value)) (*bytearray(value))
    writedataf(value, len(value))

为了测试我的理论,我创建了一个非常简单的库:

#include <stdio.h>

void writedata(unsigned char *datapos, int datanum) {
    for (int index = 0; index < datanum; index++) {
        putchar(datapos[index]);
    }
    putchar('\n');
}

我使用为 macOS 创建了一个共享库

clang -Wall -Werror -shared -fpic main.c -o libwritedata.so

我将共享库对应到 /usr/local/lib 并创建了这个 Python 脚本:

import ctypes

writedataf = ctypes.CDLL('/usr/local/lib/libwritedata.so').writedata
writedataf.argtypes = [ctypes.POINTER(ctypes.c_ubyte), ctypes.c_int]

def writedata(value):
    if isinstance(value, str):
        value = (ctypes.c_ubyte * len(value)) (*bytearray(value))
    writedataf(value, len(value))

x = "a short string"
writedata(x)
uints = (ctypes.c_ubyte * len(x)) (*bytearray(x))
writedata(uints)

输出

a short string
a short string

【讨论】:

  • +1 嗯,哦,它可以工作,但我有时会使用实际的字符/字节数组访问相同的函数,即uints = (c_ubyte*8)(*name_of_list)writedata(uints, 8)。两个都可以吗?
  • @Pygmalion 我修改了脚本来处理这两种数据类型。
  • 我真的很感谢你的努力,但这对我不起作用,因为我在 C 库中 malloc 不同的 structs 必须可用于所有功能......如果我加载这个structs 的同一个 C 库的多个实例将不可见。
  • @Pygmalion 我修改了脚本,使库只加载一次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-15
  • 2013-03-28
  • 2015-09-09
  • 2010-10-03
  • 1970-01-01
  • 2014-10-25
相关资源
最近更新 更多