㈠ 如何用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位数也不需要。我的快速算法设计完毕。