I'm trying to call a C++ function from my Python code, if I pass a Boolean or an int
it works perfectly, but if I send a string, it only prints the first character.
I am compiling with:
g++ -c -fPIC foo.cpp -Wextra -Wall -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o
python3 fooWrapper.py
Here is the C++ and Python code:
Python:
from ctypes import cdll
lib = cdll.LoadLibrary("./libfoo.so")
lib.Foo_bar("hello")
c++:
#include <iostream>
#include <string>
#include <unistd.h>
void bar(char* string){
printf("%s", string);
}
extern "C" {
void Foo_bar(char* aString){
bar(aString);
}
}
I'm aware of the Boost
Library, but i couldn't manage to download it, and this way works well excepts for strings.
Thank you for your help
The problem is that strings are passed as pointers to wchar_t
wide characters in Python 3. And in little-endian system your string can be coded in binary as
"h\0\0\0e\0\0\0l\0\0\0l\0\0\0o\0\0\0\0\0\0\0"
Which, when printed with %s
will stop at the first null terminator.
For UTF-8-encoded byte strings (char *
) you need a bytes
object. For example:
lib.Foo_bar("hello".encode())
or use bytes literals:
lib.Foo_bar(b"hello")
Even better if you had specified the correct argument types:
from ctypes import cdll, c_char_p
foo_bar = cdll.LoadLibrary("./libfoo.so").Foo_bar
foo_bar.argtypes = [c_char_p]
foo_bar(b"hello\n")
foo_bar("hello\n")
when run will output the following:
hello
Traceback (most recent call last):
File "foo.py", line 5, in <module>
foo_bar("hello\n")
ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type
i.e. the latter call that uses a string instead of bytes
would throw.
You may also process Python3 strings in C++ directly using the wchar_t
type. In that case, you need to do any necessary conversions in C++ like this:
#include <iostream>
#include <locale>
#include <codecvt>
void bar(wchar_t const* aString)
{
// Kudos: https://stackoverflow.com/a/18374698
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> convert;
std::cout << convert.to_bytes(aString) << std::endl;
}
extern "C" {
void Foo_bar(wchar_t const* aString)
{
bar(aString);
}
}
You will lose Python2 compatibility, however.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With