在尝试通过 ctypes 访问 C 结构的元素时,出现 Segfault 错误。C 结构在 C 代码中的 init 函数中创建,并将其指针返回给 Python。问题在于,在尝试访问返回结构的元素时,会发生 Segfault 错误。
这是 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
2、解决方案
解决方案 1:
- 将错误的行
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),这一点毫无意义。
解决方案 2:
- 将 test_struct 声明为 init 例程中的静态局部变量,我起初对这一点持怀疑态度。(请耐心等待,我的 C 语言有一点生疏。)C 中的静态局部变量应该在对同一函数的多次调用中保持不变,但它们的范围与自动局部变量相同——返回指向自动局部变量的指针肯定会导致 Segfault。即使在 C 的同一个翻译单元中调用该函数,这通常也能正常工作,但从 Python 调用它(并且在尝试访问该结构时立即出现 Segfault)是一个危险信号。
- 尝试在 init 例程中使用 malloc(),并返回从中获得的指针。[[[ 警告:这会导致内存泄漏。 ]]] 但是没关系;如果 Segfault 消失了,你就会知道那是问题所在。然后,您可以通过在 C 代码中提供一个调用 free() 的第二个例程并确保在使用完该结构后从 Python 代码中调用它来修复内存泄漏。
223

被折叠的 条评论
为什么被折叠?



