我正在尝试从Python代码中调用C ++函数,如果我传递布尔值或int
则效果很好,但是如果我发送字符串,则仅输出第一个字符。
我正在编译:
g++ -c -fPIC foo.cpp -Wextra -Wall -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o
python3 fooWrapper.py
这是C ++和Python代码:
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);
}
}
我知道Boost
库,但是我无法下载它,并且这种方法除了字符串以外,都能很好地工作。
谢谢您的帮助
答案 0 :(得分:2)
问题在于字符串是在Python 3中作为指向 wchar_t
wide characters 的指针传递的。在little-endian系统中,您的字符串可以二进制编码为
"h\0\0\0e\0\0\0l\0\0\0l\0\0\0o\0\0\0\0\0\0\0"
其中,当使用%s
打印时,它将在第一个空终止符处停止。
用于UTF-8编码的字节字符串(char *
)you need a bytes
object。例如:
lib.Foo_bar("hello".encode())
或使用字节文字:
lib.Foo_bar(b"hello")
如果您指定了正确的参数类型,那就更好了:
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")
运行时将输出以下内容:
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
即后者将使用字符串而不是bytes
进行调用。
答案 1 :(得分:0)
您也可以使用wchar_t
类型直接在C ++中处理Python3字符串。在这种情况下,您需要像这样在C ++中进行任何必要的转换:
#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);
}
}
但是,您将失去Python2兼容性。