一.python调用c/c++

方法1:ctypes调用c/c++动态链接库(dll或so)

import ctypes

#以下4种方法选一种ok即可
#cdecl调用方法1
dll=ctypes.cdll.LoadLibrary
lib=dll("D:/pyd/MyMath.dll") #MyMath.so
#lib=ctypes.cdll.LoadLibrary("D:/pyd/MyMath.dll")#MyMath.so
#cdecl调用方法2
lib=ctypes.CDLL("D:/pyd/MyMath.dll")#MyMath.so

#stdcall调用方法1
lib=ctypes.windll.LoadLibrary("D:/pyd/MyMath.dll")#MyMath.so
#stdcall调用方法2
lib=ctypes.WinDLL("D:/pyd/MyMath.dll")#MyMath.so

#在调用c方法前可以指定传入参数的类型和返回参数的类型
lib.Add.argtypes = [ctypes.c_double, ctypes.c_double]
lib.Add.restype = ctypes.c_double

print(lib.Add(1.5,4.0))
# print(lib.Add(ctypes.c_double(1.5), ctypes.c_double(4.0)))

注意:
1.c++代码需要按照C语言编译链接,Linux下是

extern "C"

而windows下是

extern "C" {
	__declspec(dllexport) double Add(double x, double y);
	__declspec(dllexport) double Subtract(double x, double y);
	__declspec(dllexport) double Multiply(double x, double y);
	__declspec(dllexport) double Divide(double x, double y);
}

2.加载链接库的路径可以是相对路径,不过有时会报错

3.有时结果不一定正确,需要指定输入输出参数的类型,因为ctypes模块在连接python和c/c++时数据类型存在一个映射关系,如下:

c python vs2012 调用 调试 python 调用c++库_ide


方法2:调用C/C++编写的python扩展模块(pyd)

这种方法比较好,用C/C++编写python的扩展模块,在python程序里面import进去就可以调用接口

1.pyd生成。以下是Windows VS处理情况

环境配置:

c python vs2012 调用 调试 python 调用c++库_ide_02


c python vs2012 调用 调试 python 调用c++库_Python_03


c python vs2012 调用 调试 python 调用c++库_Python_04


c python vs2012 调用 调试 python 调用c++库_python_05

cpp文件处理如下

// MyMath.cpp

#include "pch.h"

#define ENABLE_PYD	1//0:DLL 1:PYD

#if ENABLE_PYD
#include "Python.h"
#else
extern "C" {
	__declspec(dllexport) double Add(double x, double y);
	__declspec(dllexport) double Subtract(double x, double y);
	__declspec(dllexport) double Multiply(double x, double y);
	__declspec(dllexport) double Divide(double x, double y);
}
#endif

double Add(double x, double y)
{
	return x + y;
}
double Subtract(double x, double y)
{
	return x - y;
}

double Multiply(double x, double y)
{
	return x * y;
}

double Divide(double x, double y)
{
	return x / y;
}
#if ENABLE_PYD
// 封装c++函数
//1.每个定义的函数都需要一个样板函数
PyObject* MyMath_Add(PyObject* self, PyObject* args)
{
	double x, y;
	if (!PyArg_ParseTuple(args, "dd", &x, &y))
	{
		return NULL;
	}

	return Py_BuildValue("d", Add(x, y));
}
PyObject* MyMath_Subtract(PyObject* self, PyObject* args)
{
	double x, y;
	if (!PyArg_ParseTuple(args, "dd", &x, &y))
	{
		return NULL;
	}
	return Py_BuildValue("d", Subtract(x, y));
}
PyObject* MyMath_Multiply(PyObject* self, PyObject* args)
{
	double x, y;
	if (!PyArg_ParseTuple(args, "dd", &x, &y))
	{
		return NULL;
	}
	return Py_BuildValue("d", Multiply(x, y));
}
PyObject* MyMath_Divide(PyObject* self, PyObject* args)
{
	double x, y;
	if (!PyArg_ParseTuple(args, "dd", &x, &y))
	{
		return NULL;
	}
	return Py_BuildValue("d", Divide(x, y));
}
//2.方法定义-就是该module包含了哪些Methods
static PyMethodDef MyMath_methods[] = {
	{"add", MyMath_Add, METH_VARARGS, "This is an add function."},
	{"subtract", MyMath_Subtract, METH_VARARGS, "This is a subtract function."},
	{"multiply", MyMath_Multiply, METH_VARARGS, "This is a multiply function."},
	{"divide", MyMath_Divide, METH_VARARGS, "This is a divide function."},
	{NULL, NULL, 0, NULL}
};
//3.模块定义
static PyModuleDef MyMath_module = {
	PyModuleDef_HEAD_INIT,
	"MyMath",
	"My Math Module",
	0,
	MyMath_methods
};
//4.启动样板函数
PyMODINIT_FUNC PyInit_MyMath()
{
	return PyModule_Create(&MyMath_module);
}

#endif

函数介绍:
包裹函数(如MyMath_Add):它负责将Python的参数转化为C的参数(PyArg_ParseTuple),调用实际的Add,并处理Add的返回值,最终返回给Python环境。
参数解析PyArg_ParseTuple:将python的变量解析成C/C++变量,按照ii,si,ss等格式。
参数解析Py_BuildValue():和PyArg_ParseTuple()的作用相反,它是将C类型的数据结构转换成Python对象。
导出表MyMath_methods:它负责告诉Python这个模块里有哪些函数可以被Python调用。导出表的名字可以随便起,每一项有4个参数:第一个参数是提供给Python环境的函数名称,这个名称可以任取,第二个参数是包裹函数。第三个参数的含义是参数变长,第四个参数是一个说明性的字符串。导出表总是以{NULL,NULL, 0,NULL}结束。
导出函数PyInit_MyMath:这个的名字不是任取的,MyMath是module名称。导出函数中将模块名称与导出表进行连接。

2.python文件如下:

import MyMath

print(MyMath.add(1.5, 3.))
print(MyMath.subtract(1.5, 3.))
print(MyMath.multiply(1.5, 3.))
print(MyMath.divide(1.5, 3.))

print(type(MyMath.add(1.5, 3.)))

注意:
编译的pyd模块放在python文件能识别的目录,最好放在同一个目录。

方法3:调用二进制可执行文件
用python程序调用C/C++编译的可执行文件

import os
os.system('test.exe')

方法4:使用SWIG(高级)
这是一个第三方的针对python的扩展包,需要些配置文件,略。

二.C/C++调用python

待续。。。