2013-06-06 6 views
2

Я пытаюсь передать структуру в Ctypes. Но вызов функции вызывает ошибку формата.Передача структур в Ctypes

Это моя C функция:

typedef struct Point2Struct { 
    double x, y; 
    } Point2; 

Point2 test(Point2 k) 
{ 
    return k; 
} 

Вызов питона выглядит следующим образом:

class Point2(Structure): 
    _fields_ = [('x',c_double),('y',c_double)] 

lib.test.argtypes=[Point2] 
lib.test.restype=Point2 
p = Point2(1.1, 2.2) 

g = lib.test(p) 

print g.x, g.y 

Когда я вызываю функцию через CDLL, я получаю:

ValueError: Procedure called with not enough arguments (4 bytes missing) or wrong calling convention 

с WinDLL, я получаю:

ValueError: Procedure probably called with too many arguments (16 bytes in excess) 

Я скомпилировал код C в DLL, используя (Mingw) GCC под Windows 7.

gcc -shared -o test.dll test.o 

Я также попытался использовать файл .so с:

gcc -shared -Wl,-soname,test-o test.so -fPIC test.c 

Но я получаю то же самое ошибки.

Что я делаю неправильно? Должен ли я компилироваться с какой-либо конкретной опцией?

+0

Вы пытались явно добавить функцию '__declspec (dllexport)' и '__cdecl' в функцию? Или, наоборот, вы пробовали написать код C, который загружает и использует вашу DLL так же, как вы хотите, с помощью 'ctypes'? – abarnert

ответ

2

Для обработки суммарной доходности более 8 байтов, как MinGW, так и компилятор Microsoft неявно передают указатель на локальную память в вызывающем. Похоже, что ваша версия gcc по умолчанию помещает этот указатель в формулу . Однако ctypes/libffi был создан с помощью Visual Studio и ожидает соглашения Microsoft, которое обрабатывает его в вызывающем . Вот почему он жалуется на отсутствие 4 байтов.

Если вы используете GCC 4.6+, есть function attribute для того, чтобы соглашение от Microsoft:

callee_pop_aggregate_return (номер)

На 32-битным I 86- - цели, вы можете? управление этим атрибутом для суммарного возврата в память, если вызывающий абонент несет ответственность за посылку скрытого указателя вместе с остальными аргументами - число, равное нулю, или если вызываемый отвечает за посылку скрытого указателя - число, равное единице. По умолчанию i386 ABI предполагает, что вызывающая выталкивает стек для скрытого указателя.

кажется GCC 4.7 использует соглашение Microsoft в качестве значения по умолчанию для целей Windows:

Обратите внимание, что на 32-битных i386 Windows, нацелен на компилятор предполагает, что вызывающий выталкивает стек для скрытого указателя.

С моим тестом, использующим gcc 4.6.3 в Windows, он по-прежнему использовал «default i386 ABI». Установка атрибута функции решила проблему:

Point2 test(Point2 k) 
    __attribute__((callee_pop_aggregate_return(0))); 

Ваш пробег может отличаться, конечно. Еще лучше, если вы контролируете спецификацию, я думаю, что проще просто использовать явный выходной параметр, переданный по ссылке.

+0

Спасибо. Думаю, я сделаю это, передав ссылку. – Avalokitesvara

Смежные вопросы