2012-12-06 3 views
2

Я не чужд модулю python ctypes, но это моя первая попытка комбинировать C++, C и Python все в одном коде. Моя проблема, похоже, очень похожа на Seg fault when using ctypes with Python and C++, однако, похоже, я не мог решить проблему точно так же.ctypes/C++ segfault доступ к переменным-членам

У меня есть простой файл C++ называется Header.cpp:

#include <iostream> 

class Foo{ 
    public: 
     int nbits; 
     Foo(int nb){nbits = nb;} 
     void bar(){ std::cout << nbits << std::endl; } 
}; 

extern "C" { 
    Foo *Foo_new(int nbits){ return new Foo(nbits); } 
    void Foo_bar(Foo *foo){ foo->bar(); } 
} 

, который я составляю в общую библиотеку, используя:

g++ -c Header.cpp -fPIC -o Header.o 
g++ -shared -fPIC -o libHeader.so Header.o 

и простой Python обертку под названием test.py:

import ctypes as C 
lib = C.CDLL('./libHeader.so') 

class Foo(object): 
    def __init__(self,nbits): 
     self.nbits = C.c_int(nbits) 
     self.obj = lib.Foo_new(self.nbits) 

    def bar(self): 
     lib.Foo_bar(self.obj) 

def main(): 
    f = Foo(32) 
    f.bar() 

if __name__ == "__main__": 
    main() 

Я бы ожидал, что когда я вызову test.py, я должен получить numbe r 32 печатается на экране. Однако все, что я получаю, это ошибка сегментации. Если я изменю конструктор, чтобы вернуть экземпляр класса в стек (т. Е. Без вызова new), а затем обойти объект, программа выполняет как ожидалось. Кроме того, если я изменю метод bar в классе Foo, так что он не использует член nbits, программа не выполняет никаких сбоев.

У меня ограниченное понимание C++, но тот факт, что я могу сделать эту функцию ожидаемой в C и на C++, но не в Python, немного запутан. Любая помощь будет принята с благодарностью.

Обновление: Благодаря одному из приведенных ниже комментариев проблема решена. В этом случае требовалось явное объявление как restype, так и argtypes для C-функций. то есть следующий был добавлен к коду:

lib.Foo_new.restype = C.c_void_p; 
lib.Foo_new.argtypes = [C.c_int32]; 
lib.Foo_bar.restype = None; 
lib.Foo_bar.argtypes = [C.c_void_p]; 
+0

Работы для меня. Также возможно Исправление: Я предполагаю, что вы скомпилировали Header.cpp с помощью переключателя -fPIC? – udoprog

+0

Работает здесь тоже. Просьба указать gdb backtrace segfault. –

+3

Работает для меня тоже. Вы перемещаете указатель на Foo как C int, который может завершиться неудачей. Попробуйте указать функции argtypes и restype, например. 'lib.Foo_new.restype = C.c_void_p; lib.Foo_new.argtypes = [C.c_int32]; lib.Foo_bar.restype = None; lib.Foo_bar.argtypes = [C.c_void_p]' – cgohlke

ответ

0

Я хотел бы попробовать следующее:

extern "C" 
{ 
    Foo *Foo_new(int nbits) 
    { 
     Foo *foo = new Foo(nbits); 
     printf("Foo_new(%d) => foo=%p\n", nbits, foo); 
     return foo; 
    } 
    void Foo_bar(Foo *foo) 
    { 
     printf("Foo_bar => foo=%p\n", foo); 
     foo->bar(); 
    } 
} 

, чтобы увидеть, если значения foo матча.

Кроме того, вы можете захотеть взглянуть на Boost.Python, чтобы упростить создание привязок Python объектов C++.

+0

В этом случае сумма кода, который будет обернута, очень мала, поэтому я думаю, что использование Boost.Python будет излишним и добавит ненужные зависимости. – ebarr

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