• python调用c/c++写的dll


    相当于翻译了这篇文章,How to write a DLL/SO in C/C++ for Python,我的目的是为了备注一下我使用失败的情况。

    首先,作者推荐了Cython可以作为一个更好的C的python封装,我没去用,直接用vs的工具来生成如下dll吧

    1,编写源码


    C程序
    //test.c
    __declspec(dllexport) int sum(int a, int b) {
        return a + b;
    }
    C++
    //test.cpp
    #define DLLEXPORT extern "C" __declspec(dllexport)
    DLLEXPORT int sum(int a, int b) {
        return a + b;
    }

    windows用户__declspec(dllexport)是必需的,也能使程序不需要.def文件就能访问,其实我不懂啥意思,Linux用户可以忽略掉此前缀。
    C++的前缀比C又多了截extern "C",是为了避免编译器添加额外的东西,所以如果是做一个C++的dll的话,也是必须的,其实你照抄前缀就可以了。
    其实大多数示例都是直接写成extern "C" __declspec(dllexport) int sum(int a, int b) 这样的,这只是可读性的问题。
    还可以添加一个头文件,类似C#的接口,想省事就不要
    //test.h
    int sum(int, int);

    2,编译成DLL/SO


    既然是教你们直接生成dll,那么当然不是建一个类库项目,直接用vs提供的命令行工具吧,导航到test.c/test.cpp目录,然后执行:
    >cl /LD test.c
    [...]
    /out:test.dll
    /dll
    /implib:test.lib
    test.obj
       Creating library test.lib and object test.exp
    Note: cl use the file extension (.c or .cpp) to know if the source is written in C or C++.

    Linux用户用gcc/g++生成一个.so文件:
    gcc -Wall -Wextra -O -ansi -pedantic -shared test.c -o test.so
    Note: the -shared option is responsible to create the .so.
    Note: You can also use Dependency Walker or similar programs to see the list of the exported functions and check if the sum function is there.
    以上未测试

    3, 用ctypes模块访问dll/so

    从python2.5起已经默认包含了ctypes,否则请自行安装(easyinstall或pip,或下载)

    >>> from ctypes import cdll
    >>> mydll = cdll.LoadLibrary('test.dll')
    >>> mydll
    <CDLL 'test.dll', handle 10000000 at b92310>

    windows在当前目录自动搜索,Linux请传入路径:
    >>> from ctypes import cdll
    >>> mydll = cdll.LoadLibrary('/home/wolf/test.so')
    >>> mydll
    <CDLL '/home/wolf/test.so', handle 9ba7d30 at b7e55d2c>

    测试:
    >>> mydll.sum
    <_FuncPtr object at 0x00AF6918>
    >>> mydll.sum(5, 3)
    >>> 8

    ==好了,以上是原文,我的问题如下:
    1, 因为开发环境是x64,也就装了64位版的python,结果老是失败,装回32位版的,以上测试直接通过,绝对是64位的原因,哪怕这个dll是在我的64位机器上编译的。几台装了x64的python都没有调成功
    2, 下面是这样的一个C方法,需要传入一个int数组和一个字符数组

    int CCaptionApp(int times,int length, int *ids,char *message)
    {
        int n,m=0;
        for(n=0;n<length;n++)
        {
            m+=ids[n];
        }
        return m;
    }

    经实测,字符数组直接传string即可,int数组我也想如法炮制:
    >>> from ctypes import cdll
    >>> mydll = CDLL('test.dll') #顺便演示另一种加载方式,书写快一些
    >>> mydll.CCaptionApp(1,3,[3,4,5],'hello')

    输出:
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ctypes.ArgumentError: argument 3: <type 'exceptions.TypeError'>: Don't know how to convert parameter 3
    看样子这个巧是不能取的(BTW,.net直接用int[]调即可),查了下文档,其中的15.17.1.13 Array一节:
    >>> from ctypes import *
    >>> TenIntegers = c_int * 10
    >>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    >>> print ii
    <c_long_Array_10 object at 0x...>
    >>> for i in ii: print i,
    ...
    1 2 3 4 5 6 7 8 9 10
    >>>

    那就是要我们用长度构造一个数组,OK,测试:
    >>> from ctypes import *
    >>> mydll = CDLL('test.dll')
    >>> mydll.CCaptionApp(1,3,(c_Int*3)(3,4,5),'hello')
    >>> 12

    成功
  • 相关阅读:
    PHP 5.3.X 连接MS SQL Server php_mssql.dll
    Elk+redis的配置
    MongoDB增加用户认证: 增加用户、删除用户、修改用户密码、读写权限、只读权限
    在 CentOS7 上安装 MySQL5.7
    CentOS挂载新硬盘
    Linux 启动和关闭自定义命令
    CentOS7中firewall防火墙详解和配置,.xml服务配置详解
    Linux --centos7 开机启动设置
    vmware centos7 静态ip设置
    Linux下安装Nginx详细图解教程(一)
  • 原文地址:https://www.cnblogs.com/walkerwang/p/3006009.html
Copyright © 2020-2023  润新知