Python提供的许多标准模块支持C或者C++接口。我们自己也可以制作自己的模块来提供给python使用。
include文件和lib文件在python的安装目录下,如果只是普通安装的python程序,那么是没有调试用的lib文件的。只用release就可以了。
建立dll文件
VS2005-新建项目-win32-win32项目,选择dll。在住文件cpp里,增加如下代码:
#include<Python.h>
std::string Recognise_Img(const std::string url){ //返回结果 return "从dll中返回的数据... : " +url;}static PyObject* Recognise(PyObject *self, PyObject *args){ const char *url; std::string sts;if (!PyArg_ParseTuple(args, "s", &url)){ printf("error\n"); return NULL;}sts = Recognise_Img(url);return Py_BuildValue("s", sts.c_str() );}static PyMethodDef AllMyMethods[] = { {"Recognise", Recognise, METH_VARARGS},//暴露给Python的函数 {NULL, NULL} /* Sentinel */};extern "C" PYUTIL_API void initpyUtil(){ PyObject *m, *d; m = Py_InitModule("pyUtil", AllMyMethods); //初始化本模块,并暴露函数 d = PyModule_GetDict(m);}如果出现编译头错误(VS2005超级喜欢出这个问题,把临时文件都删除了还是解决不了)
就在cpp文件上右键-属性-C++ -预编译头-创建使用预编译头,选择不使用预编译头。在工具-选项-项目和解决方案-C++目录-包含文件-增加D:\python\Python25\include(看你自己的python安装目录)
库文件增加D:\python\Python25\libs正常安装的python是没有debug调试库的,如果要用debug方式编译,可以修改头文件pyconfig.h中的pragma comment(lib,"python25_d.lib")为pragma comment(lib,"python25.lib"),仍然调用release的库文件。
编译成功。
把后缀名修改成pyd。放在D:\python\Python25\Dlls目录下,或者放在你的py文件的同级目录下,优先读取本目录的pyd文件。import pyUtil
data=“123456”result = pyUtil.Recognise(data)print "the result is: "+ result运行正常。
但是有个问题,如果我们使用带有\0的字符串,比如网络收报数据。
data = struct.pack('=cI41s',chr(60),0,'123456')那么在传入的时候,就会在\0的位置被截断。我们需要把参数改变,从s改为s#static PyObject* Recognise(PyObject *self, PyObject *args)
{ const char *url;char url2[100] = {0};int len; std::string sts;if (!PyArg_ParseTuple(args, "s#", &url,&len)){ printf("error\n"); return NULL;}memcpy(url2,url,len);url2[len] = 0;sts = Recognise_Img(url);return Py_BuildValue("s#", url2,len );}同时,输出也修改为s#。注意此时参数为2个,包括一个长度。
这样就OK了。
以前我一直以为python的字符串,也同样是\0结束,后来发现,是可以包括\0的,print的时候\0作为不可打印字符,\0后面的依然可以打印出来。
struct.pack的返回值为str类型。这样什么结构都可以从python传递给c了,直接传内存里面的一段东西呗。参考和学习了这2篇文章
C里面调用python也很简单,不过感觉意义不大,没什么必要的。
===================================
更新:
以前的机制换了个win7以后不好用了,不知道为什么,但是用这样的代码就行了。
Crypt = cdll.LoadLibrary("./xxxxCrypt.so")data_buffer = create_string_buffer(len(d))
data_buffer.raw = d
rv = Crypt.xxxx_decrypt(data_buffer, len(d))
hexdump(data_buffer[:rv])
用c调用python可以参考下面的文章。http://www.cnblogs.com/eric_lgf/archive/2009/09/02/1558495.html#Python脚本,存为pytest.py
def add(a,b): print "in python function add" print "a = " + str(a) print "b = " + str(b) print "ret = " + str(a+b) return a + b// C代码调,用上面的add函数
#include <stdio.h>#include <stdlib.h>#include "C:/Python26/include/python.h"#pragma comment(lib, "C:\\Python26\\libs\\python26.lib")int main(int argc, char** argv)
{ // 初始化Python //在使用Python系统前,必须使用Py_Initialize对其 //进行初始化。它会载入Python的内建模块并添加系统路 //径到模块搜索路径中。这个函数没有返回值,检查系统 //是否初始化成功需要使用Py_IsInitialized。PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pRetVal;
Py_Initialize();
// 检查初始化是否成功 if ( !Py_IsInitialized() ) { return -1; }// 载入名为pytest的脚本(注意:不是pytest.py)
pName = PyString_FromString("pytest"); pModule = PyImport_Import(pName); if ( !pModule ) { printf("can't find pytest.py"); getchar(); return -1; } pDict = PyModule_GetDict(pModule); if ( !pDict ) { return -1; }// 找出函数名为add的函数
pFunc = PyDict_GetItemString(pDict, "add"); if ( !pFunc || !PyCallable_Check(pFunc) ) { printf("can't find function [add]"); getchar(); return -1; }// 参数进栈
pArgs = PyTuple_New(2);// PyObject* Py_BuildValue(char *format, ...)
// 把C++的变量转换成一个Python对象。当需要从 // C++传递变量到Python时,就会使用这个函数。此函数 // 有点类似C的printf,但格式不同。常用的格式有 // s 表示字符串, // i 表示整型变量, // f 表示浮点数, // O 表示一个Python对象。PyTuple_SetItem(pArgs, 0, Py_BuildValue("l",3));
PyTuple_SetItem(pArgs, 1, Py_BuildValue("l",4));// 调用Python函数
pRetVal = PyObject_CallObject(pFunc, pArgs); printf("function return value : %ld\r\n", PyInt_AsLong(pRetVal));Py_DECREF(pName);
Py_DECREF(pArgs); Py_DECREF(pModule); Py_DECREF(pRetVal);// 关闭Python
Py_Finalize(); return 0;}