我正在嘗試使用Python的ctypes庫來訪問掃描庫SANE中的一些方法。這是我第一次使用ctypes並且第一次在一年內不得不處理C數據類型,所以這裏有一個公平的學習曲線,但我認爲即使沒有這個特定的聲明也會很麻煩:使用Python的ctypes傳遞/讀取聲明爲「struct_name *** param_name」的參數?
extern SANE_Status sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only);
首先,我已經成功地處理了SANE_Status
(一個枚舉)和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
。我如何確定結果的數量? SANE文檔指定「如果函數成功執行,它將存儲一個指向由* device_list中的SANE_Device結構指向NULL結尾的指針的指針。建議?
更新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
然而,10顯然是一個任意數,我沒有確定實際結果數量的方法。當只有一個設備連接時嘗試訪問devices.contents.contents.contents[1].name
會導致分段錯誤。必須有一種處理ctypes中這些變長結構的正確方法。
我的天啊,這是一個非常徹底的答案,更好的是,它的工作原理!即便如此,我也不確定自己會不會這樣做。感謝Adam! – bouvard 2008-12-20 18:38:01