我定义了一个名为TestStruct
的简单C结构和一个init_struct
函数来创建一个实例并返回指向它的指针
#include <stdlib.h>
#include <stdio.h>
typedef struct {
int x;
int y;
char* msg;
} TestStruct;
TestStruct* init_struct(int x, int y, char* msg) {
TestStruct* p;
TestStruct initial = {x, y, msg};
p = malloc(sizeof(TestStruct));
*p = initial;
return p;
}
我使用gcc
将C代码编译成.so
文件。然后,在Python中,我想使用ctypes
创建一个可以访问C结构的所有成员的绑定
import ctypes
import os
class PyStruct(ctypes.Structure):
_fields_ = [('x', ctypes.c_int),
('y', ctypes.c_int),
('msg', ctypes.c_char_p)]
lib = ctypes.cdll.LoadLibrary(os.path.abspath('/path/to/libstruct.so'))
_init_struct = lib.init_struct
_init_struct.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_char_p]
_init_struct.restype = ctypes.POINTER(PyStruct)
myStruct = _init_struct(1, 4, ctypes.c_char_p(b'hello world'))
print(myStruct.contents.x, myStruct.contents.y, myStruct.contents.msg)
结构(x
和y
)的整数成员打印得很好,但我不知道如何打印msg
指向的字符串。我看到的不是预期的hello world
,而是字节字符串b'\x01
。我从其他阅读中得到的预感是,我正在截断真正的、较长的字符串,只显示第一个字节。你知道吗
您正在将
ctypes.c_char_p(b'hello world')
传递给init_struct
,并将赋值中指向c_char_p
块的指针复制到initial
和p
。但是,指向c_char_p
块的指针仅在调用init_struct
期间有效,也就是说,一旦init_struct
返回,该c_char_p
指针将不再有效,访问它将是未定义的行为。换句话说,您在myStruct.msg
中获取的指针的副本悬空,不应在init_struct
之外访问。你知道吗记住
ctypes
并没有违反Python的垃圾收集(GC)规则。在这一行myStruct = _init_struct(1, 4, ctypes.c_char_p(b'hello world'))
ctypes
将分配一些c_char_p
对象,复制字符串bhello world
,null终止它,并将指向该内存的原始指针传递给C端。然后运行C端,代码获取该指针的副本。当C端返回时,ctypes
释放对c_char_p
对象的引用。Python的GC发现c_char_p
不再被引用,因此它被垃圾回收。因此,最终在myStruct.msg
中得到一个悬空指针。你知道吗正确的解决方案是在
init_struct
内克隆msg
内容,并提供一个fini_struct
函数来释放克隆内存,例如:然后是python方面:
相关问题 更多 >
编程相关推荐