Returning c_char_p from Python ctypes: does the result have to be copied, and if so, how?

Question:

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?

Asked By: Michal Charemza

||

Answers:

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!
Answered By: Mark Tolonen

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
Answered By: soundarrajan v
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.