2012-04-11 4 views
5

ctypesモジュールを使用すると、POINTER(c_char)型やc_char_p型をPythonに簡単にインポートできますが、どちらもゼロ値バイトを含むPython文字列で終わることはありません。どのように0 *バイトのchar *を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)永遠に取る(画素データの640×480のブロックは、私のMac上では約2秒かかり変換)。

スタックオーバフローに関してこれに関する質問がたくさんありましたが、どちらかの人が「なぜあなたはそれをする必要がありますか?または "c_char_pはあなたが望むことをする"(これは私が上で説明した通りではありません)。

私が見てきた唯一の信頼できるアドバイスは、ここで推奨されているように、C言語のAPI PyString_FromStringAndSizeを使用することです: http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/version/Doc/FAQ.html

は本当に私の知る限りそれはcython機能、ではないのpythonだからそれは、しかしどのように役立つかを見ることができません1。

私はこれをやる必要がある理由は、私はpanda3dとkinectで作業しています。kinect c apiはunsigned char *値の配列を提供し、panda3d apiは素敵なsetPixels()呼び出しを提供しますPythonの文字列を引数として取ります。

+1

これは役立つかもしれない:http://stackoverflow.com/questions/5047536/how-do-i-build-a-python-string-from-a-raw-binary-ctype-buffer –

+0

それをかもしれませんあなたが働きたいと思うコードを提供するのにも役立ちますが、そうではありません。だから、私たちはあなたがどのようにしてそれを一緒に掛ける必要性/望みのよいアイデアを得ることができるのです。 –

答えて

5

あなたが言ったように、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] 
+0

<3は完全に動作します。 – Doug

0

私は主な質問に対する最良の答えが何であるかはわかりませんが、あなたが望むものを達成するためにPyString_FromStringAndSizeがどのように使用できるかについてのいくつかのコメントがあります。 http://docs.python.org/c-api/string.html

あなたは新しいPythonのデータは、あなたのC型定義したC/C++でのPythonモジュールを書く

  • にこれを使用することができます意味:

    PyString_FromStringAndSizeは、Python C APIの一部であります-adived-strings-with-null-characters

  • このデータ型を定義して、何らかの形で問題のC文字列へのポインタを含む引数を受け入れるPythonコンストラクタを提供することができます。何も助けなければ、コンストラクタが受け入れる引数はcytpesのc_void_pです。
  • (C/C++で)定義したコンストラクタは、メンバ変数のC文字列へのポインタを格納する必要があります。コンストラクタはC/C++で書かれているので、そのコンストラクタで可能なことは何でも可能です。

これを.dll/.pydライブラリに作成してから、任意のPythonコードにimportすることができます。

確かに、かなり複雑な手順です。うまくいけば、おそらくctypesに直接基づいた、より単純な方法を示唆している人もいます。

4

、いくつかの異なる方法があります。 c_char_p型か、c_charのポインタか、void型のポインタか、またはintのアドレスであるかどうかにかかわらず、動作します。これは厄介ではないので、ctypes.string_atが好きです。

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 
+0

BTWは、バイトのシーケンスを文字列オブジェクトにデコードして、拡張文字などを容易にすることも考えなければなりません。 – benjimin

関連する問題