2011-12-26 5 views
1

У меня проблемы с указателем на указатель на рабочую структуру. Это код, который у меня есть, который генерирует исключение «ArgumentError: аргумент 1:: ожидаемый экземпляр LP_LP_List вместо указателя на LP_LP_List».Python ctypes указатель на указатель на структуру

class List(Structure): 
    _fields_ = (
     ('head', POINTER(Node)), 
     ('tail', POINTER(Node)), 
     ('current', POINTER(Node)), 
     ('saved', POINTER(Node)), 
     ('infosize', c_int), 
     ('listsize', c_ulong), 
     ('current_index', c_ulong), 
     ('save_index', c_ulong), 
     ('modified', c_bool), 
     ('search_origin', c_int), 
     ('search_dir', c_int), 
     ) 

list_p = POINTER(List) 

create = lib.DLL_CreateList 
create.argtypes = [POINTER(POINTER(List)),] 
create.restype = POINTER(List) 
mem = POINTER(list_p)() 
retval = create(byref(mem)) 

Это похоже на рекомендованный способ сделать это, но не работает.

Спасибо за любую помощь.

Для тех, кто не хочет читать все детали ниже, чтобы найти решение, последняя часть следует читать так:

#list_p = POINTER(List) # Not needed 

create = lib.DLL_CreateList 
create.argtypes = [POINTER(POINTER(List)),] 
create.restype = POINTER(List) 
control = POINTER(List)() 
list_p = create(byref(control)) 
+0

Как он «не работает»? – dstromberg

+0

Я редактировал выше с полным исключением минус трассировка. – cnobile

+0

Зачем передавать указатель списка по ссылке, если вы возвращаете созданный список в качестве возвращаемого значения функции? Что на самом деле «создает»? – PaulMcG

ответ

3

API-интерфейс звучит как указатель передается в виде ссылки будут изменены путем создания, поэтому он должен быть передан по ссылке, а возвращаемым значением будет только что созданный список.

Если бы это было написано в "С", я предполагаю, что вы есть такой код:

List *create(List **control); 
List *control; 
List *plist; 
plist = create(&control); 

С ctypes/Python, это будет отображаться на:

create.argtypes = [POINTER(POINTER(List)),] 
create.restype = POINTER(List) 
control = POINTER(List)() 
newlist = create(byref(control)) 

ли эта работа лучше?

EDIT: Поскольку создание и изменяет переданный в параметре и возвращает созданный список, я забыл бы о возвращении и просто держать аргумент:

create.argtypes = [POINTER(POINTER(List)),] 
control = Pointer(List)() 
create(byref(control)) 

Для полноты вашего Python API , вы можете подумать о написании диспетчера контекстов, чтобы позаботиться о вызове Create (когда метод __enter__ менеджера контекста вызывается оператором with для инициализации блока управления списком) и автоматически вызывает Destroy (когда метод контекста __exit__ вызывается в конец with). Тогда ваш код Python может выглядеть следующим образом:

with listManager as ListManager(): 
    # do stuff with list managed by list manager 

# end of with statement, listManager.__exit__ is automatically called, so that Destroy always 
# gets called, even if an exception is raised - this is easier for API users than expecting them 
# to write their own try-finally code, and put Destroy in the finally block 

EDIT: - Я построил свой DLL на Ubuntu и использовать приведенный выше код Python, кажется, что это делает список после того, как все.

~/dev/python$ python 
Python 2.6.6 (r266:84292, Sep 15 2010, 16:22:56) 
[GCC 4.4.5] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> from ctypes import * 
>>> 
>>> class List(Structure): pass 
... 
>>> lib = CDLL('./libdll.so') 
>>> create = lib.DLL_CreateList 
>>> create.argtypes = [POINTER(POINTER(List)),] 
>>> create.restype = POINTER(List) 
>>> 
>>> control = POINTER(List)() 
>>> create(byref(control)) 
<__main__.LP_List object at 0x7fdc0c607e60> 

EDIT - я написал Pyparsing утилиту для чтения файла заголовка C и выход заполнителей Структура подклассы и функции argtypes и определения restype. Вот что я получил за ваш lib - он не тестировался, но может дать вам скачок в вашем тестировании API:

from ctypes import * 
ll = CDLL("./libdll.so") 

# user defined types 
class ll_Info(Structure): pass 
class ll_DLL_Boolean(Structure): pass 
class ll_DLL_SrchOrigin(Structure): pass 
class sys_select_fd_set(Structure): pass 
class ll_List(Structure): pass 
class sys_time_timeval(Structure): pass 
class ll_DLL_SrchDir(Structure): pass 
class ll_DLL_Return(Structure): pass 
class ll_DLL_SearchModes(Structure): pass 
class ll_DLL_InsertDir(Structure): pass 

# functions 
ll.DLL_CreateList.restype = POINTER(ll_List) 
ll.DLL_CreateList.argtypes = (POINTER(POINTER(ll_List)),) 
ll.DLL_DestroyList.restype = None 
ll.DLL_DestroyList.argtypes = (POINTER(POINTER(ll_List)),) 
ll.DLL_Version.restype = c_char_p 
ll.DLL_Version.argtypes =() 
ll.DLL_IsListEmpty.restype = ll_DLL_Boolean 
ll.DLL_IsListEmpty.argtypes = (POINTER(ll_List),) 
ll.DLL_IsListFull.restype = ll_DLL_Boolean 
ll.DLL_IsListFull.argtypes = (POINTER(ll_List),) 
ll.DLL_CurrentPointerToHead.restype = ll_DLL_Return 
ll.DLL_CurrentPointerToHead.argtypes = (POINTER(ll_List),) 
ll.DLL_CurrentPointerToTail.restype = ll_DLL_Return 
ll.DLL_CurrentPointerToTail.argtypes = (POINTER(ll_List),) 
ll.DLL_DecrementCurrentPointer.restype = ll_DLL_Return 
ll.DLL_DecrementCurrentPointer.argtypes = (POINTER(ll_List),) 
ll.DLL_DeleteCurrentRecord.restype = ll_DLL_Return 
ll.DLL_DeleteCurrentRecord.argtypes = (POINTER(ll_List),) 
ll.DLL_DeleteEntireList.restype = ll_DLL_Return 
ll.DLL_DeleteEntireList.argtypes = (POINTER(ll_List),) 
ll.DLL_FindNthRecord.restype = ll_DLL_Return 
ll.DLL_FindNthRecord.argtypes = (POINTER(ll_List),POINTER(ll_Info),c_ulong,) 
ll.DLL_GetCurrentRecord.restype = ll_DLL_Return 
ll.DLL_GetCurrentRecord.argtypes = (POINTER(ll_List),POINTER(ll_Info),) 
ll.DLL_GetNextRecord.restype = ll_DLL_Return 
ll.DLL_GetNextRecord.argtypes = (POINTER(ll_List),POINTER(ll_Info),) 
ll.DLL_GetPriorRecord.restype = ll_DLL_Return 
ll.DLL_GetPriorRecord.argtypes = (POINTER(ll_List),POINTER(ll_Info),) 
ll.DLL_InitializeList.restype = ll_DLL_Return 
ll.DLL_InitializeList.argtypes = (POINTER(ll_List),c_size_t,) 
ll.DLL_IncrementCurrentPointer.restype = ll_DLL_Return 
ll.DLL_IncrementCurrentPointer.argtypes = (POINTER(ll_List),) 
ll.DLL_InsertRecord.restype = ll_DLL_Return 
ll.DLL_InsertRecord.argtypes = (POINTER(ll_List),POINTER(ll_Info),ll_DLL_InsertDir,) 
ll.DLL_RestoreCurrentPointer.restype = ll_DLL_Return 
ll.DLL_RestoreCurrentPointer.argtypes = (POINTER(ll_List),) 
ll.DLL_SaveList.restype = ll_DLL_Return 
ll.DLL_SaveList.argtypes = (POINTER(ll_List),c_char_p,) 
ll.DLL_SetSearchModes.restype = ll_DLL_Return 
ll.DLL_SetSearchModes.argtypes = (POINTER(ll_List),ll_DLL_SrchOrigin,ll_DLL_SrchDir,) 
ll.DLL_StoreCurrentPointer.restype = ll_DLL_Return 
ll.DLL_StoreCurrentPointer.argtypes = (POINTER(ll_List),) 
ll.DLL_SwapRecord.restype = ll_DLL_Return 
ll.DLL_SwapRecord.argtypes = (POINTER(ll_List),ll_DLL_InsertDir,) 
ll.DLL_UpdateCurrentRecord.restype = ll_DLL_Return 
ll.DLL_UpdateCurrentRecord.argtypes = (POINTER(ll_List),POINTER(ll_Info),) 
ll.DLL_GetSearchModes.restype = POINTER(ll_DLL_SearchModes) 
ll.DLL_GetSearchModes.argtypes = (POINTER(ll_List),POINTER(ll_DLL_SearchModes),) 
ll.DLL_GetCurrentIndex.restype = c_ulong 
ll.DLL_GetCurrentIndex.argtypes = (POINTER(ll_List),) 
ll.DLL_GetNumberOfRecords.restype = c_ulong 
ll.DLL_GetNumberOfRecords.argtypes = (POINTER(ll_List),) 
+0

Сохранение переданных аргументов - это то, что люди обычно делали, однако у меня также были просьбы передать его из функции, но обычно ее отбрасывают. Я уже пробовал ваше предложение, но это тоже не сработало. newlist = Pointer (List)() <- откуда это взялось? – cnobile

+0

ОК, я, должно быть, сделал что-то неправильно в первый раз. Я переместил код и начал работать. control = POINTER (List)() newlist = create (byref (control)) теперь работает. Спасибо – cnobile

+0

Да, это так, как я уже говорил выше, я, должно быть, сделал что-то неправильно в первый раз, когда попробовал, но он работает сейчас. Спасибо еще раз за помощь. – cnobile