Reputation: 27012
I have a function in a library that returns a null-terminated char *, so setup in Python as:
my_lib = ctypes.CDLL("my_lib")
my_lib.my_func.restype = ctypes.c_char_p
and this seems to work fine:
my_bytes = my_lib.my_func()
print(my_bytes)
However, the library manages its own memory, and so may manipulate the memory pointed to by char *
later on. To make sure my_bytes
never actually changes, does it need to be copied to another Python object, or has it already been copied? If it does need to be copied, how to do this?
Upvotes: 1
Views: 1027
Reputation: 35
c_char_p
by default returns bytes object. So it will print with b'
bytes. If need to print as string, we can do with .decode('utf-8')
Example:
print(b2) # prints b'hello, world!' as bytes
print(b2.decode('utf-8')) # prints 'hello, world!' as string
Upvotes: 1
Reputation: 177610
It's already been copied. A c_char_p
return is automatically converted to an immutable Python bytes
object. If the return type was POINTER(c_char)
then you would have a pointer to the actual memory. Sometimes you need the explicit type if you need to pass that pointer to a function to free the memory later.
A quick proof:
from ctypes import *
dll = CDLL('msvcrt')
dll.strcpy.argtypes = c_char_p,c_char_p
dll.strcpy.restype = c_char_p
# strcpy returns a pointer to the destination buffer 'b'
b = create_string_buffer(30)
b2 = dll.strcpy(b,b'hello, world!')
print(b2)
b[0] = b'm' # alter the destination
print(b.value)
print(b2) # no change to b2
print()
dll.strcpy.restype = POINTER(c_char)
b3 = dll.strcpy(b,b'hello there!')
print(b3)
print(b3[:12])
b[0] = b'm' # alter the destination
print(b.value)
print(b3[:12]) # changed!
Output:
b'hello, world!'
b'mello, world!'
b'hello, world!' # no change
<ctypes.LP_c_char object at 0x000001B65E9A5840> # the pointer
b'hello there!' # copied data from pointer
b'mello there!' # change destination buffer
b'mello there!' # cpoied data from pointer again, changed!
Upvotes: 3