由于C/C++大量的使用指针,因此如何处理指针是swig的一项重要的工作。

SWIG有一个简单规则就是

Everything else is a pointer

即除了基本的类型以外的其他数据类型,swig全部通过指针来处理。大致过程就是将操作C/C++中的结构,类,数组等是通过操作指向这些数据的指针操作,封装成python的数据也是一个包含指针信息的python对象。
C/C++的指针在python中是通过一个特殊的对象来保存的,在python中的变量保存的C/C++的数组以及类对象其实就是保存的这些指针对象,然后封装函数也是操作指针来操作真正的结构和数组等对象。

下面我通过自己写的两个例子来说明:

python操作C的struct

首先是C的源程序,定义vector结构和向量相加的函数

  • vector.h

    1
    2
    3
    4
    5
    6
    7
    #include <stdio.h>
    typedef struct Vector {
    double x, y, z;
    } Vector;
    Vector add(Vector a, Vector b);
  • vector.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include "vector.h"
    Vector add(Vector a, Vector b)
    {
    Vector sum;
    sum.x = a.x + b.x;
    sum.y = a.y + b.y;
    sum.z = a.z + b.z;
    return sum;
    }

    函数的实现。

  • vector.i

    1
    2
    3
    4
    5
    6
    7
    %module vector
    %{
    #include "vector.h" // 让生成的封装函数知道原型和结构定义
    %}
    %include "vector.h" // 封装结构和函数

这样就可以在生成封装文件并一并编译链接生成最终的模块文件。

可见,封装以后可以向使用类一样使用C结构,对象的类型是一种Swig Object其中对象中包含了指针的类型和保存的地址的值。
包括按值返回的add函数也是返回一个”指针对象”。

python中操作C数组

  • array_test.h

    1
    2
    3
    #include <stdio.h>
    void show_array(int * a, int n);
  • array_test.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include "array_test.h"
    void show_array(int * a, int n)
    {
    int i;
    for (i = 0; i < n; ++i)
    printf("%d, ", a[i]);
    putchar('\n');
    }
  • array_test.i

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    %module array_test
    %{
    #include "array_test.h"
    %}
    %inline %{
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // 不仅让swig封装,还要把这个复制到生成的封装文件中
    %}
    void show_array(int *, int); // 让swig封装这个函数

现在就可以使用swig来生成最终的扩展模块库

可见,在python中操作的array也是通过一个Swig Object对象。其中放置了指针类型和指针的值。

Comments