SWIG 是一个非常优秀的开源工具,支持您将 C/C++ 代码与任何主流脚本语言相集成。
SWIG (Simplified Wrapper and Interface Generator) is anopen source software tool used to connectcomputer programs or libraries written in C or C++ with scripting languages such as Lua, Perl, PHP, Python, R,Ruby, Tcl, and other languages likeC#, Java, Go, Modula-3,OCaml, Octave, and Scheme. Output can also be in the form of XML or Lisp S-expressions.(来自于wiki)
2.1 下载地址: http://www.swig.org/download.html
2.2 将下载的文件如swig-2.0.8.tar.gz解压
2.3 进入swig-2.0.8目录,执行一下命令
./configure --prefix=/usr/program/swig/ #或者其他安装目录 make make install
./configure --prefix=/usr/progam/swig --without-pcre, 因为我使用swig的目的是python
SWIG支持多种语言(脚本),这里介绍python的一个例子,这个例子是使用c语言模拟位数组,然后交由python扩展
最后有一个使用c扩展python和直接使用python的效率比较
//Bit.h #ifndef BIT_H #define BIT_H //create: 2012-10-19 //version: 1.0 #define CHAR_LENGTH sizeof(unsigned char) //Bit模拟位操作 typedef struct { unsigned char *pArray;//指向一个字符型数组,用以存储bit位 unsigned long length;//记录pArray的长度, 字符个数 unsigned long used;//记录用户使用的bit位 }Bit; //创建Bit对象 //@len: 初始化bit位数 //@return: 返回一个指向Bit对象的指针, 该指针需要使用freeBit销毁 Bit* createBit(unsigned long len); //设置bit位 //@pb:指向Bit的一个对象, 如果为NULL, 返回1 //@index: 需要设置的bit位, 范围应当是 (0~used) //@value: bit位的值, (0,1) //@return: 成功返回0, 如果出现pb==NULL, index out of range, value!=0 and value!=1, 返回1 int setBit(Bit *pb,unsigned long index, int value); //获取bit位 //@pb:指向Bit的一个对象, 如果为NULL, 返回1 //@index: 需要设置的bit位, 范围应当是 (0~used) //@return: 成功返回0, 如果出现pb==NULL, index out of range, 返回1 int getBit(Bit *pb,unsigned long index); //返回使用的长度 //@pb: 如果pb==NULL, return -1 int bitLength(Bit *pb); //销毁Bit对象 void freeBit(Bit *pb); #endif
//Bit.c #include "Bit.h" #include <stdio.h> #include <stdlib.h> #include <limits.h> //创建Bit对象 //@len: 初始化bit位数, len>=0 //@return: 返回一个指向Bit对象的指针, 该指针需要使用freeBit销毁 Bit* createBit(unsigned long len) { if(len<0) return NULL; Bit *pb=(Bit*)malloc(sizeof(Bit)); if(len>0) { pb->length=(len-1)/CHAR_LENGTH+1; pb->pArray=(char*)malloc(sizeof(char)*pb->length); pb->used=len; }else { pb->length=0; pb->pArray=NULL; pb->used=len; } return pb; } //设置bit位 //@pb:指向Bit的一个对象, 如果为NULL, 返回1 //@index: 需要设置的bit位, 范围应当是 [0~used) //@value: bit位的值, (0,1) //@return: 成功返回0, 如果出现pb==NULL, index out of range, value!=0 and value!=1, 返回1 int setBit(Bit *pb,unsigned long index, int value) { if(pb==NULL || pb->pArray==NULL || index<0 || index>=pb->used || (value!=0 && value!=1)) return 1; unsigned long a=index/CHAR_LENGTH; unsigned long b=index%CHAR_LENGTH; if(value==0) { pb->pArray[a]&=(UCHAR_MAX^(1<<b)); //printf("%d\n",pb->pArray[a]); }else { pb->pArray[a]|=(1<<b); //printf("%d\n",pb->pArray[a]); } return 0; } //获取bit位 //@pb:指向Bit的一个对象, 如果为NULL, 返回1 //@index: 需要设置的bit位, 范围应当是 [0~used) //@return: 成功返回0, 如果出现pb==NULL, index out of range, 返回1 int getBit(Bit *pb,unsigned long index) { if(pb==NULL || pb->pArray==NULL || index<0 || index>=pb->used) return 1; unsigned long a=index/CHAR_LENGTH; unsigned long b=index%CHAR_LENGTH; //printf("%d\n",pb->pArray[a]&(1<<b)); if((pb->pArray[a]&(1<<b))==0) return 0; else return 1; } //返回使用的长度 //@pb: 如果pb==NULL, return -1 int bitLength(Bit *pb) { if(pb==NULL || pb->pArray==NULL) return -1; return pb->used; } //销毁Bit对象 void freeBit(Bit *pb) { if(pb==NULL) return; if(pb->pArray!=NULL) { free(pb->pArray); pb->pArray=NULL; } free(pb); }
//Bit.i
%module Bit #module name %{ #include "Bit.h" #加入Bit_wrap.c文件 %} #需要导出到python的函数 extern Bit* createBit(unsigned long len); extern int setBit(Bit *pb,unsigned long index, int value); extern int getBit(Bit *pb,unsigned long index); extern int bitLength(Bit *pb); extern void freeBit(Bit *pb);
使用Bit.i生成wrap文件
该命令得到Bit_wrap.c Bit.py (Bit_wrap.c是python调用c的接口封装 ,Bit.py 是向python提供接口并使用python的c库调用动态库)
[username]$ swig -python Bit.i
编译Bit.c Bit_wrap.c文件(Bit.c 是实现逻辑的文件, Bit_wrap.c是python调用c的接口封装 )
[username]$ gcc -c -fpic Bit.c Bit_wrap.c -I${PYTHON_INCLUDE}
-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),
则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意
位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
PYTHON_INCLUDE为python安装目录下的include文件夹, 如/usr/program/python/include/python.2.7
[username]$ gcc -shared Bit.o Bit_wrap.o -o _Bit.so
注意输出库文件为_Bit.so, 有下划线和模块名称组成
这里以计算一亿一下的素数个数来演示
将Bit.py和_Bit.so文件复制到需要的位置
编写prime_count.py
#coding=utf-8 #create-2012-10-17 #version: 1.0 #计算小于1亿的素数个数 import time from Bit import * MAX=100000000 count=1 #0 表示素数 #1 表示已经去除 start_time=time.time() len=MAX/2-1 b=createBit(len) def remove(idx): i=idx global b while i<len: #b[i]=1 setBit(b,i,1) i+=2*idx+3 for i in range(3,MAX,2): if getBit(b,(i-3)/2)==0: #素数 count+=1 remove((i-3)/2) end_time=time.time() print count print end_time-start_time使用方法和其他python提供的模块一样
使用以上方法(c扩展python)得到结果为:
5761455(素数个数) 113.465720892(second)
另外,如果直接使用python模拟bit,并同样计算一亿一下的素数个数,结果为
5761455(素数个数) 293.473055124(second)
可以看到,性能提升非常明显(接近3倍),当然这只是一个例子,并不具有太多代表性
另附,同样的方法,如果是c语言,调用我们实现的Bit的话结果为:
5761455(素数个数) 5(second)
计算这种事情还是交给c做比较恰当