使用 Ctypes 调用复杂的 c++ 代码
Using Ctypes to call complicated c++ code
我的问题基于这个例子。不同的是,在我的C++代码中,我有一个函数,该函数在该函数中启动自定义类的对象。在我的 python 代码中,我只想调用该函数。我不需要在 Python 中创建自定义类的对象。例如,我的C++代码中有三个文件
福.H
class foo {
public:
foo();
void bar();
int a;
};
傅.cpp
extern "C" {
foo::foo () {
a = 5;
}
void foo::bar(){
std::cout << "Hello" << std::endl;
};
}
主函数.cpp
extern "C" {
void printStuff (int addNum) {
foo fooArg;
fooArg.a = fooArg.a + addNum;
std::cout<<"Printing..."<<std::endl;
std::cout<<fooArg.a<<std::endl;
}
}
在我的 Python 代码中,我想创建一个在mainFunc.cpp
中调用printStuff
的 Python 函数。我不需要在 Python 中启动foo
对象。但是,有两个问题:
(1( 我是否正确使用了extern "C"
?
(2( 如何将这三个文件编译成一个共享库?我使用 g++。
(1( 我是否正确使用了外部"C"?
不要extern ”C"
方法定义。
extern "C"
的目的是告诉编译器某些函数需要作为 C 函数进行访问,即由 C 代码调用,或者由从共享对象加载和调用函数的ctypes
或其他库调用。
您唯一要通过ctypes
调用的函数是printStuff
,因此只有该函数应该extern "C"
。
尝试extern "C"
这些方法可能会对g++
无伤大雅(它们最终仍会在导出表中命名为__ZN3foo3barEv
(,但您可能会收到警告,甚至是未运行的库,使用不同的编译器。
(2( 如何将这三个文件编译成一个共享库?我使用 g++。
您可能想要编写Makefile
或使用其他构建系统,但如果您想手动执行此操作:
g++ -shared -o foo.so foo.cpp mainFunc.cpp
根据您的平台,您可能还需要手动指定-fPIC
或-fpic
。1
如果要单独执行这些步骤:
g++ -c foo.cpp
g++ -c mainFunc.cpp
g++ -shared -o foo.so foo.o mainFunc.o
在这种情况下,如果需要 PIC 标志,它将在前两行。
现在,从 Python 使用它:
$ python3
>>> import ctypes
>>> foo = ctypes.cdll.LoadLibrary('foo.so')
>>> foo.printStuff(10)
Printing...
15
>>> foo.printStuff("abc")
Printing...
116480373
当然,通常最好设置argtypes
和restype
,而不是ctypes
猜测。它猜测 Pythonint
10 应该转换为 Cint
10,效果很好,但它也猜测 Pythonstr
"abc"应该转换为 Cconst char *
,你最终得到指向字符串缓冲区的指针的低 32 位用作int
。所以:
>>> foo.printStuff.argtypes = [ctypes.c_int]
>>> foo.printStuff.restype = None
>>> foo.printStuff(10)
Printing...
15
>>> foo.printStuff("abc")
ArgumentError: argument 1: <class 'TypeError'>: wrong type
你可能想写一个foo.py
来总结它:
import ctypes
foo = ctypes.cdll.LoadLibrary('foo.so')
foo.printStuff.argtypes = [ctypes.c_int]
foo.printStuff.restype = None
printStuff = foo.printStuff
1. 从快速测试来看,x86_64 macOS、x86 macOS 或 x86_64 Linux 不需要它,但 PowerPC Linux 需要-fpic
,ARM64 Linux 需要-fPIC
。但是,我实际上并没有运行所有这些。而且,除了macOS(我确保使用Homebrew gcc 8.2和Apple Clang 9.1进行测试(之外,我不知道我使用的是哪个编译器版本。
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 代码在main()中运行,但在函数中出现错误
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 编译包含字符串的代码时遇到问题
- 我在c++代码中生成了一个运行时#3异常
- 如何在linux终端中同时编译和运行c++代码
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 在Linux for Windows上编译C++代码时出错
- 我的字符计数代码计算错误.为什么
- 孤立代码块在结构中引发异常
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 此代码是否违反一个定义规则
- 为什么我的代码在输出中增加了93天
- 我的简单if-else语句是如何无法访问的代码
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 为什么在这个代码结束循环中没有得到结束
- 在c代码之间共享数据的最佳方式
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值