Python ctypes, pass double pointer by reference
Problem
I am trying to use a function in c library with the following prototype: The int glip_get_backends(const char ***name, size_t *count);
argument name
here is the problem. It is a 2-dimensional char array passed by reference. In C, the function is used like this:
const char** name;
size_t count;
glip_get_backends(&name, &count);
for (size_t i = 0; i < count; i++) {
printf("- %s\n", name[i]);
}
Now I want to use this function from python using ctypes.
What i tried
The most logical approach for me was in python:
lglip = CDLL("libglip.so")
count = c_int(0)
backends = POINTER(POINTER(c_char))
lglip.glip_get_backends(byref(backends), byref(count))
resulting in an error message
TypeError: byref () must be an instance of ctypes, not `_ctypes.PyCPointerType '
The next approach was to use the function POINTER()
three times and omit byref()
, but this results in the following error:
ctypes.ArgumentError: argument 1 :: Don't know how to convert parameter 1
Then I took inspiration from this question and came up with the following:
lglip = CDLL("libglip.so")
count = c_int(0)
backends = POINTER(POINTER(c_char))()
lglip.glip_get_backends(byref(backends), byref(count))
for i in range(0, count.value):
print backends[i]
Adding ()
after definition backends
for some reason I didn't fully understand, fixed the call, but the output I get is the following:
<ctypes.LP_c_char object at 0x7f4592af8710>
<ctypes.LP_c_char object at 0x7f4592af8710>
I can't seem to be able to iterate over a 2 dimensional array with one iterator in python, since it doesn't make it dereferenced.
source to share
After realizing what the C implementation %s
uses to repeat over substrings, I came up with the following working solution:
lglip = CDLL("libglip.so")
count = c_int(0)
backends_c = POINTER(c_char_p)()
lglip.glip_get_backends(byref(backends_c), byref(count))
backends = []
for i in range(0, count.value):
backends.append(backends_c[i])
print backends
Update: changed POINTER(POINTER(c_char))()
to POINTER(c_char_p)()
as suggested by eryksun . This way I can easily access the strings.
source to share
If backend elements can use the method index
, you can use this code:
lglip = CDLL("libglip.so")
count = c_int(0)
backends = POINTER(POINTER(c_char))()
lglip.glip_get_backends(byref(backends), byref(count))
for i in range(0, count.value):
print ''.join(backends[i][:backends[i].index("0")])
source to share