如何将具有0值字节的char *转换为python字符串?

时间:2012-04-11 02:29:43

标签: python ctypes

使用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字符串作为参数。

3 个答案:

答案 0 :(得分:6)

正如您所说,使用POINTER(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]

答案 1 :(得分:6)

有几种不同的方法。我喜欢ctypes.string_at,因为它并不挑剔:无论您提供的是c_char_p类型,还是指针指向c_char,还是无效指针类型,它都能正常工作,或者即使只是一个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

答案 2 :(得分:0)

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

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

这意味着您可以将其用于

  • 在C / C ++中编写一个Python模块,在其中定义一个新的Python数据类型C-derived strings-with-null-characters
  • 您可以定义该数据类型,以便它提供一个Python构造函数,该构造函数接受以某种方式包含指向所讨论的C字符串的指针的参数。如果没有任何帮助,构造函数接受的参数可以是来自cytpes的c_void_p
  • 您定义的构造函数(在C / C ++中)必须在成员变量中存储指向C字符串的指针。它也可能会复制和/或增加引用计数等。由于构造函数是用C / C ++编写的,因此构造函数中可能存在任何可能的内容。

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

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

相关问题