6

使用 ctypes 模块,我可以轻松地将 POINTER(c_char) 或 c_char_p 类型导入 python,但它们都没有提供一种方法来结束包含零值字节的 python 字符串。

c_char_p 以零结尾,这意味着来自 C 的 char * 数组在第一个零值处终止。

POINTER(c_char) 是导入可以具有 0 值的二进制数据的推荐方法,但似乎没有办法直接将其转换为 python 字符串。

我可以做这个:

pixels = clibblah.get_pixels()
a = ""
for i in range(0, clibblah.get_pixel_length()):
    a += pixels[i]

...但是这 1) 看起来不是很 Pythony,并且 2) 需要很长时间(在我的 Mac 上转换 640x480 像素数据块大约需要 2 秒)。

我在堆栈溢出时看到了很多关于这个的问题,但是如果我能看到一个不是人们会说的“你为什么需要这样做?” 或“c_char_p 会做你想做的事”(它不会,正如我上面所描述的)。

我见过的唯一可靠的建议是使用 c api PyString_FromStringAndSize,如下所示:http: //www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/version/Doc/FAQ.html

不过,我真的看不出这有什么帮助,因为 afaik 这是一个 cython 功能,而不是 python 功能。

对于感兴趣的人,我需要这样做的原因是我正在使用 panda3d 和 kinect,而 kinect c api 提供了一个 unsigned char * 值数组,而 panda3d api 亲切地提供了一个 setPixels() 调用,它只需要一个python字符串作为参数。

4

3 回答 3

7

如您所说,使用 aPOINTER(c_char)获取指向二进制数据数组的指针。要将它们组合成一个字符串,您可以只取它的一部分,因为数组索引使用 ctypes 指针按预期工作:

clibblah = ctypes.cdll.LoadLibrary('clibblah.dylib')
get_pixels = clibblah.get_pixels
get_pixels.restype = ctypes.POINTER(ctypes.c_char)

pixels = get_pixels()
num_pixels = clibblah.get_pixel_length()

# Slice the ctypes array into a Python string
a = pixels[:num_pixels]
于 2012-04-11T03:01:08.073 回答
7

有几种不同的方法。我喜欢ctypes.string_at它,因为它并不挑剔:无论您是否提供c_char_p类型、指向指针c_char、或 void 指针类型,甚至只是一个int地址,它都可以工作。

s = b'hello\x00world' # create a string containing null bytes
sz = len(s)
from ctypes import *

p = c_char_p(s) # obtain a pointer of various types
p2 = cast(p,POINTER(c_char))
address = cast(p,c_void_p).value

print p.value # by default it is interpreted as null-terminated

print p2[:sz] # various methods of explicitly specifying the full length
print string_at(p,size=sz)
print (c_char * sz).from_address(address).raw
于 2016-08-02T02:40:49.443 回答
1

我不知道主要问题的最佳答案是什么,但这里有一些关于如何PyString_FromStringAndSize用来完成你想要的东西的评论。

PyString_FromStringAndSize是 Python C API 的一部分:http: //docs.python.org/c-api/string.html

这意味着您可以使用它来

  • 用 C/C++ 编写一个 Python 模块,在其中定义一个新的 Python 数据类型,您的 C 派生字符串与空字符
  • 您可以定义该数据类型,以便它提供一个 Python 构造函数,该构造函数接受以某种方式包含指向相关 C 字符串的指针的参数。如果没有任何帮助,构造函数接受的参数可能是c_void_p来自 cytpes。
  • 您定义的构造函数(在 C/C++ 中)必须将指向 C 字符串的指针存储在成员变量中。它还可能进行复制和/或增加引用计数等。由于构造函数是用 C/C++ 编写的,因此该构造函数中可能存在的任何事情都是可能的。

您必须将其构建到 .dll/.pyd 库中,然后才能将其构建import到任何 Python 代码中。

诚然,这是一个相当复杂的过程。希望其他人提出一种更简单的方法,可能直接基于 ctypes 。

于 2012-04-11T02:46:11.283 回答