㈠ 如何用python封裝C語言的字元串處理函數
在C語言中,字元串處理是每天都要面對的問題。我們都知道C語言中其實並沒有一種原生的字元串類型,『字元串』在C語言里只是一種特殊的以''結尾的字元數組。因此,如何將C語言與更高層次的Python語言在『字元串』處理這個問題上對接是一個有難度的問題。所幸有swig這種強大的工具。
如何封裝一個函數,它修改參數字元串的內容
假如有這樣一個C語言的函數,
<!-- 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封裝,看看運行結果。
Type "help", "right", "credits" or "license" for more information.
>>> import cchar
>>> s='123456'
>>> cchar.FillZero(s,6)
Traceback (most recent call last):
File "<stdin>", line 1, in <mole>
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);
然後運行看結果
Type "help", "right", "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的宏還有好幾個,我列舉一下:
cstring_output_allocate(char *s,free($1));
第一個參數是指向字元串地址的指針,第二個參數為釋放空間的方法。
大家考慮這一下這樣的函數:
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 -->
%mole 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返回。其實在調用的時候非常簡單,沒有參數,直接返回字元串。
如何處理c++的std::string
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);
運行結果:
Python 2.6.6 (r266:84292, Dec 27 2010, 00:02:40)
[GCC 4.4.5] on linux2
Type "help", "right", "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' 這個宏再封裝一次了。
㈡ 如何使用用Cython通過Python列表到C函數
的#include&LT;&stdio.h中GT;
#包括「test.h」
無效流行(無效){
一個[0] =將0x55;
一個[1] = 0x66;
一個[2] = 0x77;
A [3] ='\\ 0';
}
無效的putAll(INT N,焦炭C []){
的memcpy(A,C,N);
}
字元* GETALL(無效){
返回&放大器;一個[0];
}
㈢ 求十億內所有質數的和,怎麼做最快
計算時間應該在1秒內完成的。我的程序可以做到。#include <math.h>#include <stdio.h>#include <memory.h>#include <time.h>#define ST 7#define MOVE 4#define BLOCKSIZE (510510 * 8) // 2 * 3 * 5 * 7 * 11 * 13 * 17 = 510510#define MAXM ((BLOCKSIZE >> MOVE) + 1)#define SET_BIT(a, n) a[n >> 3] |= (1 << (n & 7))typedef unsigned int uint;typedef unsigned short ushort;typedef unsigned char uchar;typedef unsigned long long uint64;static ushort NumBit0[1 << 16];static uint Prime[6800];static uchar BaseTpl[MAXM * 2];static int sieve( ){ int primes = 1; const uint maxp = (1 << 16) + 1000; for (uint p = 3; p < maxp; p += 2) { if (0 == (BaseTpl[p >> MOVE] & (1 << (p / 2 & 7)))) { Prime[primes++] = p; for (uint i = p * p / 2; i < maxp / 2; i += p) SET_BIT(BaseTpl, i); } } return primes;}static void initBit( ){ memset(BaseTpl, 0, sizeof(BaseTpl)); for (int k = 1; k < ST; k++) for (int p = Prime[k] / 2; p < sizeof(BaseTpl) * 8; p += Prime[k]) SET_BIT(BaseTpl, p); for (int i = 1; i < sizeof(NumBit0) / sizeof(NumBit0[0]); i++) NumBit0[i] = NumBit0[i >> 1] + (i & 1); for (int j = 0; j < sizeof(NumBit0) / sizeof(NumBit0[0]); j++) NumBit0[j] = 16 - NumBit0[j];}static void inlinecrossOutFactorMod6(uchar bitarray[], const uint start, const uint leng, uint factor){ uint s2, s1 = factor - start % factor; s1 += factor - factor * (s1 % 2); if (start <= factor) s1 = factor * factor; const char skip[] = {0, 2, 1, 1, 0, 1}; const char mrid = ((start + s1) / factor) % 6 - 1; s1 = s1 / 2 + skip[mrid] * factor; s2 = s1 + skip[mrid + 1] * factor; for (factor += 2 * factor; s2 <= leng / 2; ) { SET_BIT(bitarray, s1); s1 += factor; //6k + 1 SET_BIT(bitarray, s2); s2 += factor; //6k + 5 } if (s1 <= leng / 2) SET_BIT(bitarray, s1);}static int inline setSieveTpl(uchar bitarray[], uint start, int leng){ const int offset = start % BLOCKSIZE; memcpy(bitarray, BaseTpl + (offset >> MOVE), (leng >> MOVE) + 2); if (start < 32) *((short*)bitarray) = 0x3491; //0x 0011 0100 1001 0001 bitarray[0] |= (1 << (offset % 16 / 2)) - 1; leng += offset % 16; *((uint*)bitarray + (leng >> 6)) |= ~((1u << (leng / 2 & 31)) - 1); return offset % 16;}static uint64 segmentedSieve(uint start, int leng){ uchar bitarray[MAXM + 64]; const int offset = setSieveTpl(bitarray, start, leng); start -= offset, leng += offset; const int maxp = (int)sqrt((double)start + leng) + 1; for (int i = ST, p = Prime[i]; p < maxp; p = Prime[++i]) crossOutFactorMod6(bitarray, start, leng, p); uint64 sum = 0; for (int i = 0; i < leng / 2; i ++) { if (!(bitarray[i >> 3] & (1 << (i & 7))))#if 0 printf("%u ", start + i * 2 + 1), sum ++;#else sum += start + i * 2 + 1;#endif } return sum;}int sievePrimes(uint start, uint stop){ uint64 primes = 0; if (start <= 2 && stop >= 2) { primes = 2; printf("%d ", 2); } const int segsize = 31 << 14; if (start + segsize > stop) return primes + segmentedSieve(start, stop - start + 1); primes += segmentedSieve(start, segsize - start % segsize); for (uint i = start / segsize + 1; i < stop / segsize; i++) primes += segmentedSieve(i * segsize, segsize); primes += segmentedSieve(stop - stop % segsize, stop % segsize + 1); return primes;}int main(int argc, char* argv[]){ uint start = 0, stop = 100000000; sieve(); initBit(); const char *ouput = "PI(%u, %u) = %lld, time use %u ms "; while (scanf("%u %u", &start, &stop) == 2 && start < stop ) { clock_t tstart = clock(); int primeCnt = sievePrimes(start, stop); printf(ouput, start, stop, primeCnt, clock() - tstart); } return 0;}//PI[1, 2147483647] = 105097565, time use 159
10億也就相當於2的32次方,根據質數定理,大概有百萬個左右。用數域篩法,現在的機器做起來都不算事情,蛋疼的人們早就把這些數算出來了。有個網站,http://prime.utm.e/list,基本把前500萬個質數都算出來了。所以,最快的演算法就是做個爬蟲,然後把這些質數抓出來,至於加法的快速演算法,似乎32位數也不需要。我的快速演算法設計完畢。