我正在尝试从ctypes访问结构的元素。该结构在C代码的init函数中创建,指向它的指针返回给Python。我遇到的问题是我在尝试访问返回结构的元素时遇到了段错误。这是代码:
C代码(我称之为ctypes_struct_test.c):
#include <stdio.h>
#include <stdbool.h>
typedef struct {
bool flag;
} simple_structure;
simple_structure * init()
{
static simple_structure test_struct = {.flag = true};
if (test_struct.flag) {
printf("flag is set in C\n");
}
return &test_struct;
}
Python代码(我称之为ctypes_struct_test.py):
#!/usr/bin/env python
import ctypes
import os
class SimpleStructure(ctypes.Structure):
_fields_ = [('flag', ctypes.c_bool)]
class CtypesWrapperClass(object):
def __init__(self):
cwd = os.path.dirname(os.path.abspath(__file__))
library_file = os.path.join(cwd,'libctypes_struct_test.so')
self._c_ctypes_test = ctypes.CDLL(library_file)
self._c_ctypes_test.init.restypes = ctypes.POINTER(SimpleStructure)
self._c_ctypes_test.init.argtypes = []
self.simple_structure = ctypes.cast(\
self._c_ctypes_test.init(),\
ctypes.POINTER(SimpleStructure))
a = CtypesWrapperClass()
print 'Python initialised fine'
print a.simple_structure.contents
print a.simple_structure.contents.flag
C在Linux下编译如下:
gcc -o ctypes_struct_test.os -c --std=c99 -fPIC ctypes_struct_test.c
gcc -o libctypes_struct_test.so -shared ctypes_struct_test.os
在运行python ctypes_struct_test.py
时,我得到以下输出:
flag is set in C
Python initialised fine
<__main__.SimpleStructure object at 0x166c680>
Segmentation fault
我正在尝试做什么,或者我尝试做的方式有问题吗?
答案 0 :(得分:4)
要使其工作,请更换错误的行
self._c_ctypes_test.init.restypes = ctypes.POINTER(SimpleStructure)
通过正确的行
self._c_ctypes_test.init.restype = ctypes.POINTER(SimpleStructure)
还要考虑删除无意义的演员
self.simple_structure = ctypes.cast(
self._c_ctypes_test.init(), ctypes.POINTER(SimpleStructure))
它从ctypes.POINTER(SimpleStructure)
投射到ctypes.POINTER(SimpleStructure)
!
答案 1 :(得分:1)
你在你的init例程中将test_struct声明为一个静态局部变量 - 我乍一看我很怀疑。 (忍受我;我的C有点生锈。)
C中的静态局部变量应该在对同一函数的多次调用中保持不变,但它们的范围与自动局部变量相同 - 并返回指向自动局部变量的指针肯定会给你一个段错误。即使你通常在C语言中从同一个翻译单元调用该函数,这通常也会起作用,你从Python调用它的事实(以及你试图访问结构时就是segffeulting)是红色的标志。
尝试在init例程中使用malloc()并返回从中获取的指针,而不是返回指向静态变量的指针。
[[[警告:这会导致内存泄漏。 ]]]
但那没关系;如果segfault消失了,你会知道这就是问题所在。然后,您可以通过在C代码中提供调用free()的第二个例程来确定内存泄漏,并确保在完成结构时从python代码中调用它。