from ctypes import *
charptr = POINTER(c_char)
test = CDLL('test.so')
test.initializetest.argtypes = []
test.initializetest.restype = charptr
test.searchtest.argtypes = [charptr]
test.searchtest.restype = c_int
buf = test.initializetest()
test.searchtest(buf)
print cast(buf, c_char_p).value
# TODO Release the "buf" memory or it will leak.
EDIT
Initially I used c_char_p to pass the buffer between the functions but c_char_p is like a const pointer. If used as a restype, you will actually get a Python str back. So for initializetest it will create a string from the allocated memory (by copying data) and throw the pointer away.
Now we're creating a new type, a POINTER to c_char. This is then used in both functions.
For Python, this type points to a single char so we have to cast it to get the whole string after searchtest is done. We cast to c_char_p because we just want to read the value so a const pointer is OK.
As a side note, this illustrates the disastrous effect of using c_char_p with functions that modify the array (as searchtest above does):
>>> libc.memset.argtypes = [c_char_p, c_int, c_int]
>>> foo = 'Python'
>>> foo
'Python'
>>> libc.memset(foo, ord('x'), 3)
44808532
>>> foo
'xxxhon'
>>>
Note how we've managed to change an immutable Python string!
The argtypes setup line isn't even needed because ctypes assumes c_char_p if Python str is used as argument.
from ctypes import *
charptr = POINTER(c_char)
test = CDLL('test.so')
test.initializetest.argtypes = []
test.initializetest.restype = charptr
test.searchtest.argtypes = [charptr]
test.searchtest.restype = c_int
buf = test.initializetest()
test.searchtest(buf)
print cast(buf, c_char_p).value
# TODO Release the "buf" memory or it will leak.
EDIT
Initially I used c_char_p to pass the buffer between the functions but c_char_p is like a const pointer. If used as a restype, you will actually get a Python str back. So for initializetest it will create a string from the allocated memory (by copying data) and throw the pointer away.
Now we're creating a new type, a POINTER to c_char. This is then used in both functions.
For Python, this type points to a single char so we have to cast it to get the whole string after searchtest is done. We cast to c_char_p because we just want to read the value so a const pointer is OK.
As a side note, this illustrates the disastrous effect of using c_char_p with functions that modify the array (as searchtest above does):
>>> libc.memset.argtypes = [c_char_p, c_int, c_int]
>>> foo = 'Python'
>>> foo
'Python'
>>> libc.memset(foo, ord('x'), 3)
44808532
>>> foo
'xxxhon'
>>>
Note how we've managed to change an immutable Python string!
The argtypes setup line isn't even needed because ctypes assumes c_char_p if Python str is used as argument.
Maybe by using restype like described here
class Test(object):
def __init__(self):
self.test_library=CDLL("./test.so")
self.test_initialize = self.test_library.initializetest
self.test_initialize.argtypes = []
self.test_initialize.restype = c_char_p # c_char_p is a pointer to a string
self.test_search = self.test_library.searchtest
self.test_search.restype = c_int
self.test_search.argtypes = [c_char_p]
self.m = c_char_p(self.test_initialize())
def search(self):
return self.test_search(self.m).value
r = Test()
print r.search()
EDIT: corrected after test :)
Thanks to @ErykSun the solution:
Python code
string1 = "my string 1"
string2 = "my string 2"
# create byte objects from the strings
b_string1 = string1.encode('utf-8')
b_string2 = string2.encode('utf-8')
# send strings to c function
my_c_function.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
my_c_function(b_string1, b_string2)
I think you just need to use c_char_p() instead of create_string_buffer().
string1 = "my string 1"
string2 = "my string 2"
# create byte objects from the strings
b_string1 = string1.encode('utf-8')
b_string2 = string2.encode('utf-8')
# send strings to c function
my_c_function(ctypes.c_char_p(b_string1),
ctypes.c_char_p(b_string2))
If you need mutable strings then use create_string_buffer() and cast those to c_char_p using ctypes.cast().
Your problem is that greeting was allocated on the stack, but the stack is destroyed when the function returns. You could allocate the memory dynamically:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
const char* hello(char* name) {
char* greeting = malloc(100);
snprintf("Hello, %s!\n", 100, name)
printf("%s\n", greeting);
return greeting;
}
But that's only part of the battle because now you have a memory leak. You could plug that with another ctypes call to free().
...or a much better approach is to read up on the official C binding to python (python 2.x at http://docs.python.org/2/c-api/ and python 3.x at http://docs.python.org/3/c-api/). Have your C function create a python string object and hand that back. It will be garbage collected by python automatically. Since you are writing the C side, you don't have to play the ctypes game.
...edit..
I didn't compile and test, but I think this .py would work:
import ctypes
# define the interface
hello = ctypes.cdll.LoadLibrary('./hello.so')
# find lib on linux or windows
libc = ctypes.CDLL(ctypes.util.find_library('c'))
# declare the functions we use
hello.hello.argtypes = (ctypes.c_char_p,)
hello.hello.restype = ctypes.c_char_p
libc.free.argtypes = (ctypes.c_void_p,)
# wrap hello to make sure the free is done
def hello(name):
_result = hello.hello(name)
result = _result.value
libc.free(_result)
return result
# do the deed
print hello("Frank")
In hello.c you return a local array. You have to return a pointer to an array, which has to be dynamically allocated using malloc.
char* hello(char* name)
{
char hello[] = "Hello ";
char excla[] = "!\n";
char *greeting = malloc ( sizeof(char) * ( strlen(name) + strlen(hello) + strlen(excla) + 1 ) );
if( greeting == NULL) exit(1);
strcpy( greeting , hello);
strcat(greeting, name);
strcat(greeting, excla);
return greeting;
}
The value received is a byte string in both Python 2 and Python 3. Python 3 displays byte string with the b'' syntax by default to indicate it is a byte (data) string and not a Unicode (text) string. If you want to process the char* as text, decode it from data bytes to text appropriately. For example if the value represents a simple ASCII string:
>>> s = b'ascii string'
>>> print(s)
b'ascii string'
>>> print(s.decode('ascii'))
ascii string
.decode() takes an encoding and converts a byte string to a Unicode string. Of course as mentioned in the other answer, you could pass a wchar_t* from C++ to the callback instead and ctypes will do the decoding for you with ctypes.wstring_at.
Another important point is ctypes will convert c_char_p to an actual Python bytes object and the address used by string_at is actually the buffer in the bytes object, which is copied from the pointer passed by C++ and stops at the first zero byte. If your callback intends to modify the buffer and intend C++ to see the changes, or the data buffer contains zero bytes and needs to process the entire length, this won't work.
C demo code:
#include <stdio.h>
typedef void (*callback)(char*,size_t);
__declspec(dllexport)
void func(callback cb) {
char data[] = {'a','b','c',0,'d','e','f'};
if(cb)
cb(data,sizeof data);
for(int i = 0; i < sizeof data; ++i)
printf("%c ",data[i]);
printf("\n");
}
Failing example with c_char_p:
from ctypes import *
dll = CDLL('./test')
CALLBACK = CFUNCTYPE(None,c_char_p,c_size_t)
@CALLBACK
def callback(s,size):
print(string_at(s,size))
s[0] = b'x'
s[1] = b'y'
s[size-1] = b'z'
print(string_at(s,size))
dll.func.argtypes = CALLBACK,
dll.func.restype = None
dll.func(callback)
Note the byte string after the zero byte is incorrect, and you can't modify the buffer:
b'abc\x00\x8b\x01\x00'
Traceback (most recent call last):
File "_ctypes/callbacks.c", line 234, in 'calling callback function'
File "C:\Users\metolone\test.py", line 9, in callback
s[0] = b'x'
TypeError: 'bytes' object does not support item assignment
a b c d e f
Passing example with POINTER(c_char) and added some display options:
from ctypes import *
dll = CDLL('./test')
CALLBACK = CFUNCTYPE(None,POINTER(c_char),c_size_t)
@CALLBACK
def callback(s,size):
print(string_at(s,size)) # display as bytes
print(string_at(s,size).decode('ascii')) # display as text
print(string_at(s,size).hex()) # display as hexadecimal
s[0] = b'x'
s[1] = b'y'
s[size-1] = b'z'
print(string_at(s,size))
dll.func.argtypes = CALLBACK,
dll.func.restype = None
dll.func(callback)
Note the buffer is correct, can be modified, and C shows the change.
b'abc\x00def' # byte string display
abc def # text string display
61626300646566 # hex string display
b'xyc\x00dez'
x y c d e z
The b'...' is the syntax for a bytes literal and not part of the string, it's telling you that the "string" is actually a bytes object, not a str. Changing %s to %r in your format string shows this more clearly:
$ python3 test.py
In py_callback(), len = 6, str = <b'foobar'>
$ python2 test.py
In py_callback(), len = 6, str = <'foobar'>
There's not a perfectly reliable way to go from char* to str because the meaning of str has changed. In Python 3, str went from being a sequence of bytes to a unicode string (the python 2 unicode type).
You can get around it in several ways.
Wrapper function for ctypes
The conversion of char* will be perfectly consistent depending on which Python major version you have -- 3 will always have bytes, 2 will always have str -- so you can write a function that you call instead of ctypes.string_at.
import sys
if sys.version_info[0] >= 3:
def c_string_at(buf, len):
return ctypes.string_at(buf, len).decode()
else:
c_string_at = ctypes.string_at
Solve it in C++ by making your callback parameter const wchar_t*
extern "C" void testLib2(void *(*callback)(const wchar_t*, size_t))
{
callback(L"foobar", 6);
}
def py_callback(buf, count):
value = ctypes.wstring_at(buf, count)
print("In py_callback(), count = %d, str = <%s>, type = %s" % (
count, value, type(value).__name__))
callback = ctypes.CFUNCTYPE(None, ctypes.c_wchar_p, ctypes.c_size_t)
_lib = ctypes.CDLL('./libfoo.so')
_lib.testLib2(callback(py_callback))
$ python2 test.py
In py_callback(), count = 6, str = <foobar>, type = unicode
$ python3 test.py
In py_callback(), count = 6, str = <foobar>, type = str
Assigning a new value to instances of the pointer types c_char_p, c_wchar_p, and c_void_p changes the memory location they point to, not the contents of the memory block (of course not, because Python strings are immutable):
>>> s = "Hello, World" >>> c_s = c_char_p(s) >>> print c_s c_char_p('Hello, World') >>> c_s.value = "Hi, there" >>> print c_s c_char_p('Hi, there') >>> print s # first string is unchanged Hello, World >>>You should be careful, however, not to pass them to functions expecting pointers to mutable memory. If you need mutable memory blocks, ctypes has a create_string_buffer function which creates these in various ways. The current memory block contents can be accessed (or changed) with the raw property, if you want to access it as NUL terminated string, use the string property:
Says the ctypes tutorial. What I gather from this is that only if the function would work with a const char*, would passing in the python string be valid. Keep in mind, it won't have a null termination.
I'd suggest using create_string_buffer anyhow.
The type ctypes.c_char_p represents a nul-terminated string. If a C function takes a const char* you can pass a Python string to it and it will receive a nul-terminated version.
A Windows example DLL:
// test.c - cl /LD test.c
#include <string.h>
__declspec(dllexport)
char* func(char* a, size_t len, const char* b) {
if(strlen(b) * 2 >= len)
return NULL;
strcpy_s(a, len, b);
strcat_s(a, len, b);
return a;
}
Python:
Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from ctypes import *
>>> x = CDLL('test')
>>> x.func.restype = c_char_p
>>> x.func.argtypes = c_char_p, c_int, c_char_p
>>> s = create_string_buffer(10)
>>> x.func(s, len(s), 'abcd')
'abcdabcd'
from ctypes import *
charptr = POINTER(c_char)
test = CDLL('test.so')
test.initializetest.argtypes = []
test.initializetest.restype = charptr
test.searchtest.argtypes = [charptr]
test.searchtest.restype = c_int
buf = test.initializetest()
test.searchtest(buf)
print cast(buf, c_char_p).value
# TODO Release the "buf" memory or it will leak.
Initially I used c_char_p to pass the buffer between the functions but c_char_p is like a const pointer. If used as a restype, you will actually get a Python str back. So for initializetest it will create a string from the allocated memory (by copying data) and throw the pointer away.
Now we're creating a new type, a POINTER to c_char. This is then used in both functions.
For Python, this type points to a single char so we have to cast it to get the whole string after searchtest is done. We cast to c_char_p because we just want to read the value so a const pointer is OK.
As a side note, this illustrates the disastrous effect of using c_char_p with functions that modify the array (as searchtest above does):
>>> libc.memset.argtypes = [c_char_p, c_int, c_int]
>>> foo = 'Python'
>>> foo
'Python'
>>> libc.memset(foo, ord('x'), 3)
44808532
>>> foo
'xxxhon'
Note how we've managed to change an immutable Python string!
The argtypes setup line isn't even needed because ctypes assumes c_char_p if Python str is used as argument.
Maybe by using restype like described here
class Test(object):
def __init__(self):
self.test_library=CDLL("./test.so")
self.test_initialize = self.test_library.initializetest
self.test_initialize.argtypes = []
self.test_initialize.restype = c_char_p # c_char_p is a pointer to a string
self.test_search = self.test_library.searchtest
self.test_search.restype = c_int
self.test_search.argtypes = [c_char_p]
self.m = c_char_p(self.test_initialize())
def search(self):
return self.test_search(self.m).value
r = Test()
print r.search()
EDIT: corrected after test :)