I'm having difficulty passing string from Python to C by ctypes:
My C code(compiled into a 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;
}
My Python code:
...
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))
...
I get the error: hello_args = TEST_STRUCT(1, name) TypeError: expected string, c_char_Array_5 found
I tried to change c_char_p to c_wchar_p or c_char*5 or c_wchar*5 etc. Sometimes it can run without error, the first int parameter of the struct can be printed correctly, but not the second string pointer, the best I can get is just the first character 't' instead of the whole word "test".
BTW, my python3 version is 3.3.0
The solution depends on whether you need the data type to be mutable (from Python's perspective).
If don't need the data to be mutable, then don't bother with the buffer constructor. Just pass the bytes
object direct to the TEST_STRUCT
constructor. eg.
from ctypes import *
class TEST_STRUCT(Structure):
_fields_ = [("a", c_int),
("b", c_char_p)]
hello_args = TEST_STRUCT(1, b"test")
If you need a mutable buffer then you need to specify your char*
type slightly differently in the TEST_STRUCT
class. eg.
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
versus POINTER(c_char)
Ostensibly, whilst these two appear similar they are subtly different. POINTER(c_char)
is for any buffer of char
data. c_char_p
is specifically for NULL terminated strings. As a side effect of this condition all c_char_p
objects are immutable (on the python side) so as to make this guarantee easier to enforce. eg. {65, 66, 67, 0}
is a string ("ABC"
), whereas {1, 2, 3}
would not be.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With