Pythonのctypes通-読み込みパラメータとして宣言された"struct_name***param_name"?
質問
私は利用しようとPythonのctypesの図書館へのアクセス方法、走査型図書館 CODE.これは私の初めての経験ctypesの初めていたCのデータ型に一年以上である公正な学習曲線のだと思いなくても、この特定の宣言をする煩わしい:
extern SANE_Status sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only);
まず、私た対応 SANE_Status
(enum) SANE_Bool
(typedefに c_int
).とっても簡単です。最初のパラメータの原因となってあえぐ者はみな、私のところの悲しみ私は知らないの"***
"表記するのも私のトレーサー弾いてたりなごみます。どんな形式の入力も可能になることができまみをリストにPythonの構造-物?参考までに、Cの構造を参照しているのは:
typedef struct
{
SANE_String_Const name; /* unique device name */
SANE_String_Const vendor; /* device vendor string */
SANE_String_Const model; /* device model name */
SANE_String_Const type; /* device type (e.g., "flatbed scanner") */
}
SANE_Device;
場所 SANE_String_Const
として定義され c_char_p
.
私のPython/ctypesのオブジェクト:
class SANE_Device(Structure):
_fields_ = [
("name", c_char_p),
("vendor", c_char_p),
("model", c_char_p),
("type", c_char_p)]
言うべきこれを取得できますが期待した動作(リストの構造-物)。すべての回答ください。
更新1:
下記を使用していたため取得する正しいSANE_Device Pythonの構造:
devices = pointer(pointer(pointer(SANE_Device())))
status = libsane.sane_get_devices(devices, c_int(0))
print status, devices, devices.contents.contents.contents.name
しかし、1)言え、2)どうしよう、ちょっとあう仕事がある場合は単一の結果です。いlen()を devices.contents.contents
または devices.contents.contents.contents
.どう思決定の数が多かった。CODE docsるかどうかを指定します"の場合の機能を実行で店舗を指すポインタがNULL終了の配列へのポインタSANE_Device構造*device_list".う方に。
更新2:
えてくださったお陰で、十項目の配列を呼び出しの最初の要素を用い:
devices = pointer(pointer(pointer((SANE_Device * 10)())))
status = libsane.sane_get_devices(devices, c_int(0))
print status, devices, devices.contents.contents.contents[0].name
しかし、が明らかに任意の数字にとっての決定の数は実人数に結果が得られます。アクセスしようとしている devices.contents.contents.contents[1].name
に接続されている原因のセグメンテーション。がある必要があります適切に対処する方法は変数の長さを構築しまうこctypes.
解決
A const SANE_Device ***
は、三つのレベルのポインター:このポインタをポインタをポインタを一定SANE_Device.利用できるプログラム cdecl を読み解く複雑なC/C++の型定義.
に応じて ソ書, SANE_get_devices()
すポインタを格納、NULLで終わるリストのポインタのソデバイスの場合。このように、適切な方法では、宣言変数の型 const SANE_Device **
(ポインタをポインタ定数`SANE_Device、パスのアドレスのポインター:
const SANE_Device **device_list;
SANE_get_devices(&device_list, local_only); // check return value
// Now, device_list[0] points to the first device,
// device_list[1] points to the second device, etc.
// Once you hit a NULL pointer, that's the end of the list:
int num_devices = 0;
while(device_list[num_devices] != NULL)
num_devices++;
// num_devices now stores the total number of devices
現在、こうして呼び出すとよいでしょうからCのコードです。私は脱脂の文書ctypesで使いたい byref
関数の引数を参考に値を渡すべきポインタをポインタをSANE_Device.注この区別 pointer
や POINTER
:前作のポインタを インスタンス, であるのに対し、後者を生成し、ポインタ タイプ.このように、私の推測は次のコードです:
// SANE_Device declared as you had it
devices = POINTER(POINTER(SANE_Device))() // devices is a NULL pointer to a pointer to a SANE_Device
status = libsane.sane_get_devices(byref(devices), c_int(0))
if status != successful: // replace this by whatever success is
print error
else:
num_devices = 0
// Convert NULL-terminated C list into Python list
device_list = []
while devices[num_devices]:
device_list.append(devices[num_devices].contents) // use .contents here since each entry in the C list is itself a pointer
num_devices += 1
print device_list
[編集]かに上記のコードを用いた簡単なプレースホルダーのための SANE_get_devices
, です。