简体   繁体   中英

How to handle array of strings (char **) in ctypes in a 64-bit environment?

I'm using ctypes to work with libgphoto2 in Python. The following code succeeds on a 32-bit machine, but fails with a Segmentation Fault on a 64-bit machine (Linux, Ubuntu):

import ctypes

gp = ctypes.CDLL('libgphoto2.so')
a = gp.gp_library_version(0)
x = ctypes.c_char_p.from_address(a)
x.value

libphoto2, ctypes and python are all from repositories, so I assume that the problem is in my code; I need to consider pointers in a more general way or something like that. gp_library_version() returns const char ** , an array of string constants. Other gp_* functions work fine.

The problem is that, by default, ctypes assumes that all functions return int , which is 32 bits. But, on a 64-bit system, a pointer is 64 bits, so you're dropping the upper 32 bits from the pointer return value, so you then get a segfault when you try to dereference that invalid pointer.

You can change the expected return type of a function by assigning a type to its restype attribute like so:

gp = ctypes.CDLL('libgphoto2.so')
gp.gp_library_version.restype = ctypes.POINTER(ctypes.c_char_p)
a = gp.gp_library_version(0)
print a[0].value

If you don't annotate anything about functions in ctypes, it is assumed that they return 32bit integers. In 32 bit processes, these integers and pointers are mostly interchangeable - not so for 64 bit builds.

Just doing

gp.gp_library_version.restype = ctypes.c_void_p

before your call should suffice in this case (You will still need the x = ctypes.c_char_p.from_address(a) line).

Check the API docs on wether you should free this pointer yourself after yu use it (probably yes in this case).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM