C/C++与python互相调用
2015-12-08 16:01
609 查看
https://www.zhihu.com/question/23003213 知乎详细总结
http://blog.csdn.net/taiyang1987912/article/details/44779719 实例
http://blog.csdn.net/magictong/article/details/8947892 实例
毕业设计需要用到C++与python混合编程,这里简单的归纳并实践了一下基本方法。
void Py_Initialize(void)
初始化Python解释器,如果初始化失败,继续下面的调用会出现各种错误,可惜的是此函数没有返回值来判断是否初始化成功,如果失败会导致致命错误。
int Py_IsInitialized(void)
检查是否已经进行了初始化,如果返回0,表示没有进行过初始化。
void Py_Finalize()
反初始化Python解释器,包括子解释器,调用此函数同时会释放Python解释器所占用的资源。
int PyRun_SimpleString(const char *command)
实际上是一个宏,执行一段Python代码。
PyObject* PyImport_ImportModule(char *name)
导入一个Python模块,参数name可以是*.py文件的文件名。类似Python内建函数import。
PyObject* PyModule_GetDict( PyObject *module)
相当于Python模块对象的dict属性,得到模块名称空间下的字典对象。
PyObject* PyRun_String(const char* str, int start,PyObject* globals, PyObject* locals)
执行一段Python代码。
int PyArg_Parse(PyObject* args, char* format, …)
把Python数据类型解析为C的类型,这样C程序中才可以使用Python里面的数据。
PyObject* PyObject_GetAttrString(PyObject *o, char*attr_name)
返回模块对象o中的attr_name 属性或函数,相当于Python中表达式语句,o.attr_name。
PyObject* Py_BuildValue(char* format, …)
和PyArg_Parse刚好相反,构建一个参数列表,把C类型转换为Python对象,使得Python里面可以使用C类型数据。
PyObject* PyEval_CallObject(PyObject* pfunc, PyObject*pargs)
此函数有两个参数,而且都是Python对象指针,其中pfunc是要调用的Python 函数,一般说来可以使用PyObject_GetAttrString()获得,pargs是函数的参数列表,通常是使用Py_BuildValue()来构建。
PyObject* pyParams = PyTuple_New(2);
也可以直接使用PyObject* Py_BuildValue(char *format, …) 函数来直接来构造tuple,此函数的使用也很简单,记住一些转换的格式常量即可轻松进行转换(格式常量有点类似printf)。譬如s 表示字符串,i表示整型变量,f表示浮点数,o表示一个Python对象等等。
python_called.py
在同目录下建C文件或者C++文件
main.cpp
在Windows平台下,打开Visual Studio命令提示符,编译命令为
在Linux下编译命令为
在Mac OS X 下的编译命令同上
编译完后运行可执行文件
注意:
被调用的python文件必须与C++编译出来的可执行文件放在一个目录。
可以建vs2013工程或者Qt工程或则makefile工程文件,在里面配置include和lib目录,更方便。
python_called.py
建C/C++文件
main.cpp
同样采用命令行或者IDE配置依赖项后编译执行。
运行结果
注意:
同样的py文件必须和C/C++可执行文件在同一个目录。
PyRun_SimpleString方式其实是读一段字符串程序,可以用FILE或者fstream读进来文本文件然后传入也行,这样就可以用相对目录了。
不建议用PyRun_SimpleFile的方式,因为这个API要求传入一个FILE指针,而微软的几个CRT版本FILE指针的定义有了变化,因此传入你使用VS2005编译的FILE指针或者其它版本的FILE极有可能崩溃,如果你想安全调用,最好是自己把Python的源代码使用和应用程序相同的环境一起编译出lib来使用。
cpp_dll.cpp
在linux或者mac下用命令行编译成so
也可以在makefile里面配置
在windows下用vs2013的命令行编译从dll
在windows下也可以用IDE生成dll
main.py
运行main.py即可
注意:
C++代码需要加extern “C”来按照C语言编译链接
装在动态库的路径可以用相对路径
函数介绍:
包裹函数_add_func。它负责将Python的参数转化为C的参数(PyArg_ParseTuple),调用实际的add_function,并处理add_function的返回值,最终返回给Python环境。
参数解析PyArg_ParseTuple,将python的变量解析成C/C++变量,按照ii,si,ss等格式
导出表CppModuleMethods。它负责告诉Python这个模块里有哪些函数可以被Python调用。导出表的名字可以随便起,每一项有4个参数:第一个参数是提供给Python环境的函数名称,这个名称可以任取,第二个参数是_add_function,即包裹函数。第三个参数的含义是参数变长,第四个参数是一个说明性的字符串。导出表总是以{NULL,NULL, 0,NULL}结束。
导出函数initcpp_module。这个的名字不是任取的,是你的module名称添加前缀init。导出函数中将模块名称与导出表进行连接。
在windows下,用vs2013命令行编译成pyd文件,这个文件就可以被python识别成扩展模块
也可以在IDE里面配置编译选项生成。
在linux或者mac系统下命令编译
main.py
运行main.py文件
注意:
按照C语言编译链接
编译的模块放在python文件能识别的目录,最好放在同一个目录
cppexec.cpp
用命令行或者IDE编译成exe等执行文件
main.py
注意:
可执行文件放在python文件可识别的目录,最好同一目录
http://blog.csdn.net/taiyang1987912/article/details/44779719 实例
http://blog.csdn.net/magictong/article/details/8947892 实例
毕业设计需要用到C++与python混合编程,这里简单的归纳并实践了一下基本方法。
C/C++调用python
python作为一种胶水语言可以很灵活的嵌入到C++和java等主语言里面进行互操作实现扩展功能。方法1:使用python提供的C接口(基础)
使用python提供给C/C++的API,将python程序编程文本形式的动态链接库,可以热更新,非常方便。API介绍
以下是一些API的介绍:void Py_Initialize(void)
初始化Python解释器,如果初始化失败,继续下面的调用会出现各种错误,可惜的是此函数没有返回值来判断是否初始化成功,如果失败会导致致命错误。
int Py_IsInitialized(void)
检查是否已经进行了初始化,如果返回0,表示没有进行过初始化。
void Py_Finalize()
反初始化Python解释器,包括子解释器,调用此函数同时会释放Python解释器所占用的资源。
int PyRun_SimpleString(const char *command)
实际上是一个宏,执行一段Python代码。
PyObject* PyImport_ImportModule(char *name)
导入一个Python模块,参数name可以是*.py文件的文件名。类似Python内建函数import。
PyObject* PyModule_GetDict( PyObject *module)
相当于Python模块对象的dict属性,得到模块名称空间下的字典对象。
PyObject* PyRun_String(const char* str, int start,PyObject* globals, PyObject* locals)
执行一段Python代码。
int PyArg_Parse(PyObject* args, char* format, …)
把Python数据类型解析为C的类型,这样C程序中才可以使用Python里面的数据。
PyObject* PyObject_GetAttrString(PyObject *o, char*attr_name)
返回模块对象o中的attr_name 属性或函数,相当于Python中表达式语句,o.attr_name。
PyObject* Py_BuildValue(char* format, …)
和PyArg_Parse刚好相反,构建一个参数列表,把C类型转换为Python对象,使得Python里面可以使用C类型数据。
PyObject* PyEval_CallObject(PyObject* pfunc, PyObject*pargs)
此函数有两个参数,而且都是Python对象指针,其中pfunc是要调用的Python 函数,一般说来可以使用PyObject_GetAttrString()获得,pargs是函数的参数列表,通常是使用Py_BuildValue()来构建。
C++向Python传递参数
C++向Python传参数是以元组(tuple)的方式传过去的,因此我们实际上就是构造一个合适的Python元组就可以了,要用到PyTuple_New,Py_BuildValue,PyTuple_SetItem等几个函数,其中Py_BuildValue可以有其它一些的替换函数。PyObject* pyParams = PyTuple_New(2);
PyObject* pyParams1= Py_BuildValue("i",5); PyObject* pyParams2= Py_BuildValue("i",6); PyTuple_SetItem(pyParams,0, pyParams1); PyTuple_SetItem(pyParams,1, pyParams2); pRet = PyEval_CallObject(pFunc, pyParams);
也可以直接使用PyObject* Py_BuildValue(char *format, …) 函数来直接来构造tuple,此函数的使用也很简单,记住一些转换的格式常量即可轻松进行转换(格式常量有点类似printf)。譬如s 表示字符串,i表示整型变量,f表示浮点数,o表示一个Python对象等等。
Py_BuildValue("") None Py_BuildValue("i",123) 123 Py_BuildValue("iii",123, 456, 789) (123, 456, 789) Py_BuildValue("s","hello") 'hello' Py_BuildValue("ss","hello", "world") ('hello', 'world') Py_BuildValue("s#","hello", 4) 'hell' Py_BuildValue("()") () Py_BuildValue("(i)",123) (123,) Py_BuildValue("(ii)",123, 456) (123, 456) Py_BuildValue("(i,i)",123, 456) (123, 456) Py_BuildValue("[i,i]",123, 456) [123, 456] Py_BuildValue("{s:i,s:i}", "abc", 123, "def", 456) {'abc': 123, 'def': 456} Py_BuildValue("((ii)(ii))(ii)", 1, 2, 3, 4, 5, 6) (((1, 2), (3, 4)), (5, 6))
C++获得Python的返回值
Python传回给C++的都是PyObject对象,因此可以调用Python里面的一些类型转换API来把返回值转换成C++里面的类型。类似PyInt_AsLong,PyFloat_AsDouble这些系列的函数。Python比较喜欢传回一个元组,可以使用PyArg_ParseTuple这个函数来解析。这个函数也要用到上面的格式常量)。还有一个比较通用的转换函数是PyArg_Parse,也需要用到格式常量。源代码测试
建一个python文件python_called.py
def add_func(x,y): return x+y
在同目录下建C文件或者C++文件
main.cpp
#include <iostream> #include "Python.h" //这里要包含头文件 //C/C++中调用python函数的函数,这里采用单返回值 int function_from_python(int a,int b) { //初始化 Py_Initialize(); //定义参数 int res; PyObject *pModule=NULL; PyObject *pFunc=NULL; PyObject *pArgs=NULL; PyObject *pResult=NULL; //导入被调用的py文件名 if(!(pModule=PyImport_Import(PyString_FromString("python_called")))) { std::cout<<"get module failed!"<<std::endl; exit(0); } //获得要调用的函数名 if(!(pFunc=PyObject_GetAttrString(pModule, "add_func"))) { std::cout<<"get func failed!"<<std::endl; exit(0); } //传入参数 pArgs=Py_BuildValue("ii",a,b); //执行函数 pResult=PyObject_CallObject(pFunc, pArgs); //返回值为C++ res = PyInt_AsLong(pResult); //释放 if(pArgs) Py_DECREF(pArgs); if(pFunc) Py_DECREF(pFunc); Py_Finalize(); return res; } int main() { std::cout<<"C/C++ call python function:"<<std::endl; std::cout<<function_from_python(3,5)<<std::endl; return 0; }
在Windows平台下,打开Visual Studio命令提示符,编译命令为
cl main.cpp -I C:\Python27\include C:\Python27\libs\python27.lib
在Linux下编译命令为
g++ main.cpp -o main -I/usr/include/python2.7/ -lpython2.7
在Mac OS X 下的编译命令同上
编译完后运行可执行文件
C/C++ call python function: 8
注意:
被调用的python文件必须与C++编译出来的可执行文件放在一个目录。
可以建vs2013工程或者Qt工程或则makefile工程文件,在里面配置include和lib目录,更方便。
方法2:调用python文件并执行(基础)
还可以使用C/C++直接执行python文件程序,在控制台中运行。源代码测试
建一个python文件python_called.py
def add_func(x,y): return x+y
a=13
b=10
print "the result by python func:"
print add_func(a,b)
建C/C++文件
main.cpp
#include <iostream> #include "Python.h" //这里要包含头文件 //C/C++中执行python文件 void exec_python_file() { //初始化 Py_Initialize(); //choose1,执行单纯的内嵌字符串python代码,建议使用 if(!PyRun_SimpleString("execfile('python_called.py')")) std::cout<<"execute python file program failed"<<std::endl; //choose2,执行python文件,不建议使用 // char fileStr[]="python_called.py"; // FILE *fp; // if(!(fp=fopen(fileStr,"r"))) // std::cout<<"open python file failed!"<<std::endl; // if(!PyRun_SimpleFile(fp,fileStr)) // std::cout<<"execute python file failed!"<<std::endl; // fclose(fp); //释放资源 Py_Finalize(); } int main() { std::cout<<"C/C++ call python function:"<<std::endl; exec_python_file(); return 0; }
同样采用命令行或者IDE配置依赖项后编译执行。
运行结果
C/C++ call python function: the result by python func: 23
注意:
同样的py文件必须和C/C++可执行文件在同一个目录。
PyRun_SimpleString方式其实是读一段字符串程序,可以用FILE或者fstream读进来文本文件然后传入也行,这样就可以用相对目录了。
不建议用PyRun_SimpleFile的方式,因为这个API要求传入一个FILE指针,而微软的几个CRT版本FILE指针的定义有了变化,因此传入你使用VS2005编译的FILE指针或者其它版本的FILE极有可能崩溃,如果你想安全调用,最好是自己把Python的源代码使用和应用程序相同的环境一起编译出lib来使用。
方法3:使用Cpython(高级)
这是python的一个第三方组件,把Python代码直接变成C代码,此处略。python调用C/C++
方法1:调用C/C++动态链接库(基础)
将C/C++的程序不经任何加工直接编译成动态链接库so或者dll,再使用python的ctypes调用即可源代码测试
此处仅以linux下的so为例,因为windows下VS2013生成dll还有个导出库很麻烦。cpp_dll.cpp
#include <iostream> extern "C" void add_func(int a,int b) { std::cout<<"the result: "<<a+b<<std::endl; }
在linux或者mac下用命令行编译成so
g++ -o cpp_dll.so -shared -fPIC cpp_dll.cpp
也可以在makefile里面配置
在windows下用vs2013的命令行编译从dll
cl /LD cpp_dll.cpp -I C:\Python27\include C:\Python27\libs\python27.lib
在windows下也可以用IDE生成dll
main.py
import ctypes dll=ctypes.cdll.LoadLibrary lib=dll("./cpp_dll.so") #in windows use dll print "python call cpp dll:" lib.add_func(2,3)
运行main.py即可
注意:
C++代码需要加extern “C”来按照C语言编译链接
装在动态库的路径可以用相对路径
方法2:调用C/C++编写的python扩展模块(基础)
这种方法比较好,用C/C++编写python的扩展模块,在python程序里面import进去就可以调用接口源代码测试
cpp_called.cpp#include "Python.h" extern "C" int add_func(int a,int b) { return a+b; } extern "C" static PyObject *_add_func(PyObject *self, PyObject *args) { int _a,_b; int res; if (!PyArg_ParseTuple(args, "ii", &_a, &_b)) return NULL; res = add_func(_a, _b); return PyLong_FromLong(res); } extern "C" static PyMethodDef CppModuleMethods[] = { { "add_func", _add_func, METH_VARARGS, "" }, {NULL, NULL, 0, NULL} }; extern "C" PyMODINIT_FUNC initcpp_module(void) { (void) Py_InitModule("cpp_module", CppModuleMethods); }
函数介绍:
包裹函数_add_func。它负责将Python的参数转化为C的参数(PyArg_ParseTuple),调用实际的add_function,并处理add_function的返回值,最终返回给Python环境。
参数解析PyArg_ParseTuple,将python的变量解析成C/C++变量,按照ii,si,ss等格式
导出表CppModuleMethods。它负责告诉Python这个模块里有哪些函数可以被Python调用。导出表的名字可以随便起,每一项有4个参数:第一个参数是提供给Python环境的函数名称,这个名称可以任取,第二个参数是_add_function,即包裹函数。第三个参数的含义是参数变长,第四个参数是一个说明性的字符串。导出表总是以{NULL,NULL, 0,NULL}结束。
导出函数initcpp_module。这个的名字不是任取的,是你的module名称添加前缀init。导出函数中将模块名称与导出表进行连接。
在windows下,用vs2013命令行编译成pyd文件,这个文件就可以被python识别成扩展模块
cl /LD cpp_called.cpp /o cpp_module.pyd -I C:\Python27\include C:\Python27\libs\python27.lib
也可以在IDE里面配置编译选项生成。
在linux或者mac系统下命令编译
g++ -fPIC -shared cpp_called.cpp -o cpp_module.so -I /usr/include/python2.7/ -lpython2.7
main.py
from cpp_module import add_func print "python call C/C++ function:" print add_func(7,12)
运行main.py文件
python call C/C++ function: 19
注意:
按照C语言编译链接
编译的模块放在python文件能识别的目录,最好放在同一个目录
方法3:调用二进制可执行文件(基础)
用python程序调用C/C++编译的可执行文件cppexec.cpp
#include <iostream> int add_func(int a,int b) { return a+b; } int main() { std::cout<<"the C/C++ run result:"<<std::endl; std::cout<<add_func(2,3)<<std::endl; return 0; }
用命令行或者IDE编译成exe等执行文件
main.py
import os cpptest="cppexec.exe" #in linux without suffix .exe if os.path.exists(cpptest): f=os.popen(cpptest) data=f.readlines() #read the C++ printf or cout content f.close() print data print "python execute cpp program:" os.system(cpptest)
注意:
可执行文件放在python文件可识别的目录,最好同一目录
方法4:使用 SWIG(高级)
这是一个第三方的针对python的扩展包,需要些配置文件,略。相关文章推荐
- c语言怎么会有这么多的作用域?
- 一个简单的三子棋游戏(c语言实现)
- c语言中递归函数真的好吗?
- c语言中对可变参数列表的简单理解
- c语言中统计二进制位中1的个数的算法优化
- c语言最强大之处--指针
- C语言中的动态内存分配
- C语言基础--函数和结构体
- VC++实现Windows中双显示器(主屏、扩展屏)各种操作的源码工程
- C语言成长学习题(十五)
- C++ 语法
- Java和C/C++的差异总结
- C++之动态配置ip信息
- C++之编码实现ping的功能
- C++动态链接库测试实例
- C++动态链接库测试实例
- C++之数据库处理代理模块
- C语言-输入任意长度字符串
- C++ Builder UnicodeString 笔记
- VC++中的Error spawning cl.exe