Python ctypes-查看返回结构的c_char_p字段
我定义了一个名为Python ctypes-查看返回结构的c_char_p字段,python,c,struct,binding,ctypes,Python,C,Struct,Binding,Ctypes,我定义了一个名为TestStruct的简单C结构和一个函数init\u 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
的简单C结构和一个函数init\u 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;
}
结构的整数成员(
x
和y
)打印得很好,但我不知道如何打印msg
指向的字符串。我看到的不是预期的helloworld
,而是一个字节字符串b'\x01
。我从其他阅读中得到的直觉是,我正在截断真正的较长字符串,只显示第一个字节。您正在将ctypes.c_char_p(b'hello world')
传递到init_struct
并将赋值中指向c_char_p
块的指针复制到initial
和p
。但是,指向c\u char\u p
块的指针仅在调用init\u struct
期间有效,也就是说,一旦init\u struct
返回,c\u char\u p
指针将不再有效,访问它将是未定义的行为。换句话说,您在myStruct.msg
中获取的指针副本是悬空的,不应在init\u struct
之外访问
请记住,ctypes
并不违反Python的垃圾收集(GC)规则。在这一行中,myStruct=\u init\u struct(1,4,ctypes.c\u char\u p(b'hello world'))
ctypes
将分配一些c\u char\u p
对象,在字符串bhello world
中复制,空终止它,并将指向该内存的原始指针传递到c端。然后C端运行,代码获取该指针的副本。当C端返回时,ctypes
释放对C\u char\p
对象的引用。Python的GC然后发现c\u char\p
不再被引用,因此它被垃圾收集。因此,您最终会在myStruct.msg
中看到一个悬空指针
正确的解决方案是克隆msg
中的init_-struct
内容,并提供fini_-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 = malloc(sizeof(TestStruct));
p->x = x;
p->y = y;
p->msg = strdup(msg);
return p;
}
void fini_struct(TestStruct* p) {
free(p->msg);
free(p);
}
也许您需要将bytestream转换为string?仅供参考,您可以直接传递
b'hello world'
,而无需使用ctypes.c_char_p(b'hello world')
wrapping.about:p=malloc(sizeof(TestStruct))*p=初始值代码>1)应始终检查(!=NULL)返回值,以确保发送到mallloc
的操作成功。2) 第二条语句不会复制initial的内容。建议使用:
strncpy(p,&initial,sizeof(TestStruct))`
#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 = malloc(sizeof(TestStruct));
p->x = x;
p->y = y;
p->msg = strdup(msg);
return p;
}
void fini_struct(TestStruct* p) {
free(p->msg);
free(p);
}
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)
_fini_struct = lib.fini_struct
_fini_struct.argtypes = [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)
# when you are done with myStruct
_fini_struct(myStruct)