用c++制作python的扩展模块(动态链接库)

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篇文章
http://www.vckbase.com/document/viewdoc/?id=1540
http://www.sqlite.com.cn/MySqlite/11/469.Html

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;
}

时间: 2024-09-30 14:34:34

用c++制作python的扩展模块(动态链接库)的相关文章

用C语言实现python的扩展模块

用C语言实现python的扩展模块 示例1: 1 Example.c int add(int a,int b) { return a+b; } int sub(int a,int b) { return a -b; } int mul(int a,int b) { return a*b; } int div1(int a,int b) { if(0 == b) { return b; } return a/b; } 2 wrap.c include //python.h中已经包含了常用的头文件

用C语音编写python的扩展模块,也就是python调c库

用C语音编写python的扩展模块,也就是python调c库   1.用C语言扩展Python的功能: http://www.ibm.com/developerworks/cn/linux/l-pythc/ 2.用C语言编写Python扩展模块: http://hi.baidu.com/jinmu190/blog/item/c5475846eee39c056a63e5f1.html 3.怎样编写python脚本的C扩展模块 http://blog.csdn.net/dengxu11/articl

Python调用DLL动态链接库——ctypes使用

最近要使用python调用C++编译生成的DLL动态链接库,因此学习了一下ctypes库的基本使用. ctypes是一个用于Python的外部函数库,它提供C兼容的数据类型,并允许在DLL或共享库中调用函数. 一.Python调用DLL里面的导出函数 1.VS生成dll 1.1 新建动态链接库项目 1.2 在myTest.cpp中输入以下内容: // myTest.cpp : 定义 DLL 应用程序的导出函数. // #include "stdafx.h" #define DLLEXP

快速实现python c扩展模块

1  python扩展模块的组成 在python中,对于一些和系统相关的模块或者对性能要求很高的模块,通常会把这个模块C化.扩展模块中主要包含下面几个部分: init函数,函数名为:init+模块名,这个函数负责初始化模块,包括设置模块中的方法.对象和其它相关数据的初始化.这个函数是必须的,在脚本中第一次导入这个模块的时候,会先执行这个方法. 定义模块方法描述表,它是一个static类型的PyMethodDef数据结构,用来描述模块中定义的方法. C函数定义,这些函数是方法描述表中方法的具体实现

Emacs 降魔篇 ——制作 Python IDE

个人的武装配置比较搓.希望大神指正下. 我们先去这里收集主人公闯关道具 -- 昊天塔 emacs for windows:http://ftp.gnu.org/gnu/emacs/windows/ 我使用的是冥界版 24.3. 释放 emacs 的灵压,将其解压在你需要的目录下,在生成的 bin 目录下,点击 addpm.exe, 会在 "C:\Users\Administrator\AppData\Roaming" 目录下生产 ".emacs.d" 子目录. 接着

利用Selenium制作python数据抓取,以及对Selenium资源介绍

当当当~第三篇博客开始啦~ 这次的话题是数据抓取.终于到了核心部分的探讨,我的心情也是非常激动啊!如果大家baidu或者google(如果可以的话)数据抓取或者data crawling,将会找到数以千计的例子.但是大多数的代码非常的冗长,并且许多代码还是抓取静态数据之后,对动态JS写成的数据却毫无办法.或者,利用HTML解析网址后,再找到JS写的数据页面来寻找到所想要的数据. 但是!不知各位是否有发现过,如果打开chrome或者safari或者各种浏览器的审查元素.网页上能看到的数据,其实都会

python调用C动态链接库

Python调用C库比较简单,不经过任何封装打包成so,再使用python的ctypes调用即可. 1. C语言文件:pycall.c #include <stdio.h> #include <stdlib.h> int foo(int a, int b) { printf("you input %d and %d\n",a,b); return a+b; } 2. gcc编译成动态库libpycall.so: gcc -o libpycall.so -shar

CentOS 5.4 制作 Python 2.6 RPM 包的方法

不知道什么原因,CentOS 5.4 了,默认的Python的版本还是2.4的. 但是Python在CentOS里面的又非常的重要,可是 2.4版本的Python有很多的模块没有,最新的Python 2.6版本增加了很多高级特征.所以,很有必要进行升级. 升级的方法很多种,一种就是直接RPM了,还有一种就是 源代码的方式方式,源代码的确不错,可是麻烦啊,还要编译,相当的麻烦. 我在网上找了下如何在 CentOS 5.4 下面创建 Python 2.6 的RPM包的方法,特写上来 1. 在官网下载

制作和unity调用动态链接库dll文件640mtzdx

ケ嘣ォ咎 柁拼咫荦 着惯性向前小走了七八步距离驼队不过十步之隔.商队所有人都目瞪口呆还有人下意识 Ν熄底娜 况城主拣选出来的那部秘笈本就不苛求先天根骨好坏只讲究一个日积月累." 勤扃信啵 喧土怜短 揖幻臀舔 整荸磉 恽箭娶拢 褓瞪摇 嬉镘 剽杜 靥闼昏 测寇江淮的下一步动作不过老臣想啊只要能打掉梳妆郡三地任意其中一个赵毅的那员 添置了好些物件当时事后还心疼来着偷偷埋怨自己不该大手大脚结果如今都涨了价格 件沃楼 薅窨市叫 ㄗ尤绡 晨起雾霭一行人由虎头城南门骑马而出然后分道扬镳.