【问题标题】:Pass ByteArray from Python to C function将 ByteArray 从 Python 传递给 C 函数
【发布时间】:2017-07-15 12:20:27
【问题描述】:

我想将一个 ByteArray 变量从我的 Python 程序传递给我用 C 编写的 DLL,以加速一些在 Python 中太慢的特定处理。我浏览了 Web,尝试了结合 byref、cast、memoryviews、addressof 的 Ctypes,但没有任何效果。有没有什么简单的方法可以实现这一点,而无需将我的 ByteArray 复制到其他可以通过的东西中? 这是我想要做的:

/* My C DLL */
__declspec(dllexport) bool FastProc(char *P, int L)
{
    /* Do some complex processing on the char buffer */
    ;
    return true;
}

# My Python program
from ctypes import *
def main(argv):
    MyData = ByteArray([1,2,3,4,5,6])
    dll = CDLL('CHELPER.dll')
    dll.FastProc.argtypes = (c_char_p, c_int)
    dll.FastProc.restype = c_bool

    Result = dll.FastProc(MyData, len(MyData))
    print(Result)

但是在将第一个参数 (MyData) 传递给 C 函数时出现类型错误。

是否有任何不需要太多开销的解决方案会浪费我的 C 函数的好处?

奥利维尔

【问题讨论】:

  • 什么是ByteArray?不应该是bytearray(全部小写)吗?你在使用 Python 3 吗?
  • 是的,它是一个字节数组,抱歉打错了
  • 创建一个长度相同的 ctypes 数组类型并将bytearray 传递给它的from_buffer 构造函数,例如L = len(MyData);P = (ctypes.c_char * L).from_buffer(MyData);dll.FastProc(P, L).
  • 是的,感谢 eryksun,from_buffer 将允许 c_char 数组与原始 bytearray 共享其字节。我一回到家就去测试。阅读更多文档,我还发现将我的 C 函数与 Cython 连接是另一种选择。我将尝试这两个选项并比较性能。
  • 我确认解决方案有效,并允许我的 C 例程在原始字节数组上就地工作(包括修改)。现在我需要尝试 Python 选项,我认为它更优雅(直接调用函数)和更高效。

标签: python c ctypes


【解决方案1】:

我假设ByteArray 应该是bytearray。我们可以使用create_string_buffer 创建一个可变字符缓冲区,它是ctypes 数组c_char。但是create_string_buffer接受bytearray,我们需要传递一个bytes 对象来初始化它;幸运的是,在bytesbytearray 之间进行转换既快速又高效。

我没有你的 DLL,所以为了测试数组的行为是否正确,我将使用 libc.strfry 函数来打乱它的字符。

from ctypes import CDLL, create_string_buffer

libc = CDLL("libc.so.6") 

# Some test data, NUL-terminated so we can safely pass it to a str function.
mydata = bytearray([65, 66, 67, 68, 69, 70, 0])
print(mydata)

# Convert the Python bytearray to a C array of char
p = create_string_buffer(bytes(mydata), len(mydata))

#Shuffle the bytes before the NUL terminator byte, in-place.
libc.strfry(p)

# Convert the modified C array back to a Python bytearray
newdata = bytearray(p.raw)
print(newdata)

典型输出

bytearray(b'ABCDEF\x00')
bytearray(b'BFDACE\x00')

【讨论】:

  • 嗯,乍一看我以为你已经找到了解决方案,但我去了 create_string_buffer 的文档,我的理解是它创建了一个新对象并在其中 xopies 原始字节数组。这就是为什么最后你打印 newdata 而不是 mydata。到目前为止,我更希望我的函数就地处理原始字节数组,而不需要任何副本。字节数组是可变的,不应该违反 Python 法律。我发现推荐 SWIG 的帖子来实现我想要的,我需要深入研究一下。非常感谢您的帮助,我发现了 create_string_buffer 函数
猜你喜欢
  • 2015-10-21
  • 2014-02-22
  • 2012-03-16
  • 2022-11-24
  • 1970-01-01
  • 2017-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多