本文作为Python调用c++的进阶实现,简单的实现参考文章Python调用c++高级(swig)
通过Python调用c++文件,生成一个序列,包含10个随机的(0,1)序列,涉及到python为c++函数提供指针型变量和数组型变量。
c++实现的头文件:
//DataGen.h
#ifndef DATAGEN_H
#define DATAGEN_H
#include
#include
#define FrameLen 1024
#define MASK 12349876
#define IA 16807
#define IM 2147483647
#define AM (1.0/IM)
#define IQ 127773
#define IR 2836
//#include "101_UserType.h"
//#include "102_UserDefine.h"
double ran0(long *idum);
double GaussNoise(double Sigma, long *idum);
void randombit_gene(int *output, int length, long *seed);
int randint(long *idum);
#endif
c++实现的源文件:
//DataGen.cpp
#include "DataGen.h"
//函数实现
c++实现生成长度为10的int型数组:
#include
#include "../DataGen.h"
using namespace std;
long SeEd=1234;
int main()
{
int *SourceBit = new int[FrameLen];
randombit_gene(SourceBit, FrameLen, &SeEd);
delete [] SourceBit;
return 0;
}
实现过程为:
先直接给出swig配置文件(之后使用命令行生成动态链接库.so文件)和Python执行文件
/* File: DataGen.i */
%module DataGen
//用来生成指针
%include "cpointer.i"
//用来生成数组
%include "carrays.i"
%pointer_class(long, long_p);
%array_class(int, intArray);
%include "DataGen.h"
%{
#include "DataGen.h"
%}
命令行生成动态链接库.so文件,生成后就可以import了
$swig -c++ -python DataGen.i
$g++ -fPIC -shared DataGen_wrap.cxx DataGen.cpp -o _DataGen.so -I/usr/include/python2.7/ -lpython2.7
Python执行文件调用randombit_gene函数并输出:
#DataGen.py
import DataGen
# FrameLen = 10
seed = DataGen.long_p()
DataGen.long_p.assign(seed,123453L)
SourceBits = DataGen.intArray(10)
DataGen.randombit_gene(SourceBits, 10, seed)
for i in range(10):
print i,SourceBits[i]
执行后输出为:
0 0
1 0
2 1
3 1
4 0
5 1
6 1
7 1
8 0
9 1
Python产生可以由c++使用的指针和数组,这里需要使用swig中提供的两个库:
swig通过这两个库便可以使python可以产生指针和数组(都是地址字符串,Python本身无法使用,只是作为参数传递给c++库的接口(swig编辑了该接口),然后swig编辑的接口将该参数翻译(cpointer.i和carray.i)为c++地址,由c++库使用。
以下内容翻译自swig官方文档:
cpointer.i模块定义了可以用于用来产生围绕简单C指针包装宏。此模块的主要用途是生成指向原始数据类型(如int和double)的指针 。
在swig配置文件.i添加如下指令就可以调用cpointer.i中的函数
%include "cpointer.i"
见代码中第二行:
/* File: DataGen.i */
%module DataGen
//用来生成指针
%include "cpointer.i"
//用来生成数组
%include "carrays.i"
%pointer_class(long, long_p);
%array_class(int, intArray);
%include "DataGen.h"
%{
#include "DataGen.h"
%}
cpointer,i库下有两个函数可以调用
这两个函数都可以实现指针的生成,后一种简单但只能针对简单指针类型(基本类型)
生成一个用于处理指针类型的四个函数的集合:
type *new_name()
//创建一个新的type类型的对象并返回一个指向它的指针。在C中,该对象是使用calloc()创建的。在C ++中,使用new创建的。
type *copy_name(type value)
//创建一个新的type类型的对象并返回一个指向它的指针。初始值是通过从值复制来设置的。在C中,该对象是使用calloc()创建的。在C ++中,使用新的。
type *delete_name(type *obj)
//Deletes an object type type.
void name_assign(type *obj, type value)
//赋值 *obj = value.
type name_value(type *obj)
//Returns the value of *obj
使用此宏时,type可以是任何类型,name必须是目标语言的合法标识符。 name不应该与接口文件中使用的任何其他名称相对应。
这是一个使用%pointer_functions()的简单例子:
%module example
%include“cpointer.i”
/*创建一些函数来处理"int *"*/
%pointer_functions(int,intp);
/*使用"int *"的函数*/
void add(int x,int y,int * result);
现在,在Python中:
import example
c = example.new_intp()#为存储结果创建一个“int”
example.add(3,4,c)#调用函数
example.intp_value(c)#解除引用
7
example.delete_intp(c)#删除
在基于类的界面中 包装一个type*的指针。这个接口如下:
struct name {
name(); // Create pointer object
~name(); // Delete pointer object
void assign(type value); // Assign value
type value(); // Get value
type *cast(); // Cast the pointer to original type
static name *frompointer(type *); // Create class wrapper from existing
// pointer
};
当使用这个宏时,type被限制在一个简单的类型名称,比如int,float或者Foo。指针和其他复杂的类型是不允许的。 名称必须是尚未使用的有效标识符。当一个指针被封装为一个类时,“类”可以被透明地传递给任何需要该指针的函数。
如果目标语言不支持代理类,则使用此宏将产生与%pointer_functions()宏相同的函数示例。
应该注意的是,类接口确实引入了一个新的对象,或者将一个指针包装在一个特殊的结构中。相反,原始指针直接使用。
下面是使用一个类的例子:
%模块示例
%include“cpointer.i”
/* Wrap a class interface around an "int *" */%
%pointer_class(int, intp);
/* A function that uses an "int *" */
void add(int x, int y, int *result);
现在,在Python(使用代理类)
import example
c = example.intp()#为存储结果创建一个“int”
example.add(3,4,c)#调用函数
c.value()#Dereference
7
在这两个宏中,当使用简单的指针时,%pointer_class可能是最方便的。这是因为指针是类似于对象的访问方式,并且可以很容易地进行垃圾收集(销毁指针对象破坏了底层对象)。
这个模块定义了一些宏,这些宏有助于将普通的C指针作为数组来包装。该模块不提供任何安全性或额外的包装层 - 它仅提供用于创建,销毁和修改原始C数组数据的内容的功能。
在swig配置文件.i添加如下指令就可以调用cpointer.i中的函数
%include "carrays.i"
见代码中第三行:
/* File: DataGen.i */
%module DataGen
//用来生成指针
%include "cpointer.i"
//用来生成数组
%include "carrays.i"
%pointer_class(long, long_p);
%array_class(int, intArray);
%include "DataGen.h"
%{
#include "DataGen.h"
%}
cpointer,i库下有两个函数可以调用
array_functions(type,name)将会产生4个函数:
type *new_name(int nelements)
//创建类型的对象的一个新的type型数组。在C中,数组是使用calloc()分配的 。在C ++中,使用new []。
type *delete_name(type *ary)
//删除一个数组。在C中,使用free()。在C ++中,使用delete []。
type name_getitem(type *ary, int index)
//返回值 ary [index]。
void name_setitem(type *ary, int index, type value)
//赋值 ary[index] = value.
使用此宏时,type可以是任何类型,name必须是目标语言的合法标识符。name不应该与接口文件中使用的任何其他名称相对应。
这里是一个%array_functions()的例子。假设你有这样的功能:
void print_array(double x[10]) {
int i;
for (i = 0; i < 10; i++) {
printf("[%d] = %g\n", i, x[i]);
}
}
swig配置文件时,可以这样写:
%module example
%include "carrays.i"
%array_functions(double, doubleArray);
void print_array(double x[10]);
现在,在Python中
import example
c = example.new_doubleArray(10) # Create an array
for i in range(0,10):
example.doubleArray_setitem(a,i,2*i) # Set a value
print_array(c) # Pass to C
example.delete_doubleArray(a) # Destroy array
在基于类的界面中 包装一个type*型的指针。这个接口如下:
struct name {
name(int nelements); // Create an array
~name(); // Delete array
type getitem(int index); // Return item
void setitem(int index, type value); // Set item
type *cast(); // Cast to original type
static name *frompointer(type *); // Create class wrapper from
// existing pointer
};
当使用这个宏时,type被限制为一个简单的类型名称,比如int或者float。指针和其他复杂的类型是不允许的。 name必须是尚未使用的有效标识符。当一个指针被封装为一个类时,它可以透明地传递给任何需要该指针的函数。
与代理类结合使用时,%array_class()宏特别有用。例如:
%module example
%include“carrays.i”
%array_class(double,doubleArray);
void print_array(double x [10]);
允许你这样做:
import example
c = example.doubleArray(10) # Create double[10]
for i in range(0,10):
c[i] = 2*i # Assign values,可以直接访问c[i]
example.print_array(c) # Pass to C