Reputation: 919
In C
I have a function that expects array of unsigned char
s
void writedata(unsigned char *datapos, int datanum)
I would like to pass a standard string from Python instead
writedata = parallel.writedata
writedata.argtypes = [POINTER(c_ubyte), c_int]
a = "test string"
writedata(a, 11)
As far as I understand, string is actually an array of bytes/chars, and a
is a pointer. However, ctypes
disagrees:
ctypes.ArgumentError: argument 2: <type 'exceptions.TypeError'>: expected LP_c_ubyte instance instead of str
How can I get "real" pointer from a string?
EDIT: David Cullen provided a solution that takes string pointer as a parameter:
writedata.argtypes = [c_char_p, c_int]
That's fine, but I would like to supply both byte arrays and strings to the function. This means that this should also work
ll = [0,1,2,3,4,5,6,7]
uints = (c_ubyte*8)(*ll)
writedata(uints, 8)
I am curious why I can't do both, because in terms of memory I think byte arrays and strings should be the same? Perhaps this is all about pointer conversions?
I also tried make two ctypes
connections to the same C
function, and this does not work.
SOLUTION: I have reformulated the question and received the best answer here:
https://stackoverflow.com/a/64838842/2957687
Upvotes: 1
Views: 993
Reputation:
We can use the same function if we convert strings to match the required argument types:
def writedata(value):
if isinstance(value, str):
value = (ctypes.c_ubyte * len(value)) (*bytearray(value))
writedataf(value, len(value))
To test my theory, I created a very simple library:
#include <stdio.h>
void writedata(unsigned char *datapos, int datanum) {
for (int index = 0; index < datanum; index++) {
putchar(datapos[index]);
}
putchar('\n');
}
I created a shared library for macos using
clang -Wall -Werror -shared -fpic main.c -o libwritedata.so
I coped the shared library to /usr/local/lib
and created this Python script:
import ctypes
writedataf = ctypes.CDLL('/usr/local/lib/libwritedata.so').writedata
writedataf.argtypes = [ctypes.POINTER(ctypes.c_ubyte), ctypes.c_int]
def writedata(value):
if isinstance(value, str):
value = (ctypes.c_ubyte * len(value)) (*bytearray(value))
writedataf(value, len(value))
x = "a short string"
writedata(x)
uints = (ctypes.c_ubyte * len(x)) (*bytearray(x))
writedata(uints)
Output
a short string
a short string
Upvotes: 1