将字符串作为c_ubyte数组传递给C

时间:2020-11-12 19:37:33

标签: python c ctypes

C中,我有一个函数,期望包含unsigned char s的数组

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数组 string 。这意味着这也应该起作用

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

1 个答案:

答案 0 :(得分: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