Michal Charemza
Michal Charemza

Reputation: 27012

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

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

Answers (2)

soundarrajan v
soundarrajan v

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

Mark Tolonen
Mark Tolonen

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

Related Questions