在C語言中,字符串處理是天天都要面對的問題。咱們都知道C語言中其實並無一種原生的字符串類型,‘字符串’在C語言裏只是一種特殊的以'\0'結尾的字符數組。所以,如何將C語言與更高層次的Python語言在‘字符串’處理這個問題上對接是一個有難度的問題。所幸有swig這種強大的工具。python
假若有這樣一個C語言的函數,linux
<!-- lang: cpp --> void FillZero(char* pc,size_t * piLen) { size_t i=0; while(i++<*piLen/2 ) *pc++ = '0'; *pc = 0; *piLen = i+1; }
這個函數的功能是把字符串變成n個0。不過咱們更關注函數的形式。這樣的函數,表面上看char* pc是函數的參數,但是實際上它纔是函數的返回值和執行的結果。piLen這個參數既是pc的最大長度,也是新的字符串的長度。咱們直接用python封裝,看看運行結果。c++
<!-- lang: python --> Type "help", "copyright", "credits" or "license" for more information. >>> import cchar >>> s='123456' >>> cchar.FillZero(s,6) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: in method 'FillZero', argument 2 of type 'size_t *'
結果差強人意,不是咱們想要獲得的結果。函數的第二個參數爲size_t* 咱們很難用python來表示,並且python中也不存在既是輸入,也是輸出的參數。數組
swig有一個標準庫,其中有一個cstring.i文件就是用來解決C語言字符串類型的問題。函數
咱們在.i文件中加入這樣幾行工具
<!-- lang: cpp --> %include "cstring.i" %cstring_output_withsize(char* pc,size_t* pi) void FillZero(char* pc, size_t* pi);
而後運行看結果spa
<!-- lang: python --> Type "help", "copyright", "credits" or "license" for more information. >>> import cchar >>> cchar.FillZero(10) '00000\x00' >>> s=cchar.FillZero(10) >>> print s 00000
咱們看函數的變化。首先在python裏, FillZero變成了只有一個參數的函數。而後函數的返回值變成了一個字符串。其實cstring_output_size實際上是一個宏,經過這個宏的定義改變了函數的形式,直接在Python中獲得咱們想要的結果。指針
其實相似cstring_output_size的宏還有好幾個,我列舉一下:code
cstring_output_allocate(char **s,free(*$1)); 第一個參數是指向字符串地址的指針,第二個參數爲釋放空間的方法。 你們考慮這一下這樣的函數:orm
<!-- lang: cpp -->
void foo(char* & s) { s = (char*)malloc(10); memcpy(s,"123456789",9); }
s這個參數表面上看是輸入,其實是函數真正的輸出。 函數中真正改變的東西是char*&s指向的字符串的值。並且char*&這個類型, python或者其餘腳本語言裏應該都沒有對應的類型。那麼咱們用cstring_output_allocate將這個函數轉換成另一個形式的python或者其餘腳本語言的函數。轉換後的函數實際上是這樣的,以python爲例str foo()。
<!-- lang: cpp --> %module a %include "cstring.i" %{ void foo(char*& s); %} %cstring_output_allocate(char *&s, free(*$1)); void foo(char *&s); 在python中的調用: <!-- lang: python --> >>> import a >>> a.foo() '123456789' >>>
cstring_output_maxsize(char *path, int maxpath); 第一個參數也是能夠改變的字符串首地址,第二個參數爲字符串的最大長度。在Python中調用的時候,只有maxpath這個參數,返回字符串。
cstring_output_allocate(char **s, free(*$1)); 第一個參數爲指向字符串首地址的指針,第二個參數爲釋放指針的方法。這個宏主要是封裝一種直接在函數內部malloc空間的函數。在Python中調用時沒有參數,直接返回字符串。
cstring_output_allocate_size(char **s, int slen, free($1)); 這個至關於前面兩個函數的組合。在函數內部malloc空間,而後將字符串長度經過slen返回。其實在調用的時候很是簡單,沒有參數,直接返回字符串。
std::string是C++標準類庫STL中常見的類。在平時工做中你們確定是沒少用。在python中如何封裝std::string? swig提供了標準庫
例如函數:
<!-- lang: cpp --> string Repeat(const string& s) { return s+s; }
只要在swig中加入這樣幾行:
<!-- lang: cpp --> %include "std_string.i" using namespace std; string Repeat(const string& s);
運行結果:
<!-- lang: python --> Python 2.6.6 (r266:84292, Dec 27 2010, 00:02:40) [GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import cchar >>> cchar.Repeat('123') '123123'
使用起來很方便,但須要注意的是,假如函數的參數的內容是能夠被修改,就不能用這種方式封裝。 例如:
<!-- lang: cpp --> void repeat(string s) { s+=s; }
這樣的函數直接使用 'std_string.i' 就是無效的。遇到這種函數,只能用C語言封裝成 void repeat(chars, int maxsize), 再用swig調用 'cstring_output_withsize' 這個宏再封裝一次了。
本文代碼能夠今後下載: https://dl.dropbox.com/u/35106490/swig7.tgz