我很难通过ctypes将字符串从Python传递到C:
我的C代码(编译成hello.so)
...
typedef struct test{
unsigned int a;
unsigned char* b;
} my_struct;
int hello(my_struct *in) {
FILE *fp;
...
fprintf(fp, "%d\t%s\n", in->a, in->b);
fclose(fp);
return 0;
}
我的Python代码:
...
from ctypes import *
...
class TEST_STRUCT(Structure):
_fields_ = [("a", c_int),
("b", c_char_p)]
...
hello_lib = ctypes.cdll.LoadLibrary("hello.so")
hello = hello_lib.hello
hello.argtypes = [POINTER(TEST_STRUCT)]
name = create_string_buffer(b"test")
hello_args = TEST_STRUCT(1, name)
hello(ctypes.byref(hello_args))
...
我收到错误: hello_args = TEST_STRUCT(1,name) TypeError:期望的字符串,找到c_char_Array_5
我试图将c_char_p更改为c_wchar_p或c_char * 5或c_wchar * 5等。有时它可以正常运行,结构的第一个int参数可以正确打印,但不是第二个字符串指针,我能做到最好get只是第一个字符't'而不是整个单词“test”。
BTW,我的python3版本是3.3.0
答案 0 :(得分:1)
解决方案取决于您是否需要数据类型是可变的(从Python的角度来看)。
如果不需要数据是可变的,那么请不要打扰缓冲区构造函数。只需将bytes
对象直接传递给TEST_STRUCT
构造函数即可。例如
from ctypes import *
class TEST_STRUCT(Structure):
_fields_ = [("a", c_int),
("b", c_char_p)]
hello_args = TEST_STRUCT(1, b"test")
如果您需要可变缓冲区,则需要在char*
类中略微指定TEST_STRUCT
类型。例如
from ctypes import *
class TEST_STRUCT(Structure):
_fields_ = [("a", c_int),
("b", POINTER(c_char))] # rather than c_char_p
name = create_string_buffer(b"test")
hello_args = TEST_STRUCT(1, name)
c_char_p
与POINTER(c_char)
表面上看,虽然这两者看起来很相似但却略有不同。 POINTER(c_char)
适用于char
数据的任何缓冲区。 c_char_p
专门用于NULL终止字符串。作为此条件的副作用,所有c_char_p
对象都是不可变的(在python端),以便使此保证更容易实施。例如。 {65, 66, 67, 0}
是一个字符串("ABC"
),而{1, 2, 3}
则不是。