从Python调用C++函数

5

我正在尝试从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库,但是我无法下载它,除了字符串以外这种方法都很好用。谢谢你的帮助。


2
告诉我,%i 是做什么用的? - Jonathon Reinhart
另外,为什么你声称这是C++,而实际上你写的是C呢? - Jonathon Reinhart
1
刚刚改成了 %s,之前试过用整数。 - Chronoxx
你应该考虑向Python提交文档错误报告。在他们的手册中,[Python 3]使用C或C++扩展Python并没有涉及到这个主题。wchar_t只在一个地方出现但没有解释。wchar_t和宽字符也没有被解释。 - jww
对于那些投票关闭的人:这不是一个打字错误,而是缺乏理解从Python调用C++函数所需的内容。即使您认为它是一个打字错误,它也不是“以一种不太可能帮助未来读者的方式解决”的错误。被接受的答案很可能会帮助未来遇到类似问题的访问者。虽然这个问题很可能有重复(我没有查看),但它不应该被关闭为“打字错误:不太可能帮助未来读者”。 - Makyen
显示剩余2条评论
2个回答

5
问题在于,在Python 3中,字符串被作为指向wchar_t宽字符的指针传递。在小端系统中,您的字符串可以被编码为二进制形式。
"h\0\0\0e\0\0\0l\0\0\0l\0\0\0o\0\0\0\0\0\0\0"

使用%s打印时,会在第一个空终止符处停止。


对于UTF-8编码的字节串(char *),你需要一个bytes对象。例如:

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 的后一个调用将会抛出异常。

谢谢你的回答,非常有效! - Chronoxx

1
您也可以直接在C++中使用类型处理Python3字符串。在这种情况下,您需要像这样在C++中进行任何必要的转换:
#include <iostream>
#include <locale>
#include <codecvt>

void bar(wchar_t const* aString)
{
    // Kudos: https://dev59.com/-G445IYBdhLWcg3wiq8i#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的兼容性,然而保留HTML。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接