isdigit php,C中诸如isdigit

)

{returnc>='0'&&c

}

我当初甚至认为,这种写法已经是非常高效了。直到某一天我开始学习Linux kernel source,我才真正见识了前辈的高效算法,真的眩的令人膛目结舌。下面这段代码摘自Linux 0.11 kernel,大家看看再说:)

0/*

0  *  linux/lib/ctype.h

0  *

1  *  (C) 1991  Linus Torvalds

2  */3

4 #define _U0x01/* upper */5#define _L0x02/* lower */6#define _D0x04/* digit */7#define _C0x08/* cntrl */8#define _P0x10/* punct */9#define _S0x20/* white space (space/lf/tab) */10#define _X0x40/* hex digit */11#define _SP0x80/* hard space (0x20) */12

13externunsigned char _ctype[];14externchar _ctmp;15

16#define isalnum(c) ((_ctype+1)[c]&(_U|_L|_D))17#define isalpha(c) ((_ctype+1)[c]&(_U|_L))18#define iscntrl(c) ((_ctype+1)[c]&(_C))19#define isdigit(c) ((_ctype+1)[c]&(_D))20#define isgraph(c) ((_ctype+1)[c]&(_P|_U|_L|_D))21#define islower(c) ((_ctype+1)[c]&(_L))22#define isprint(c) ((_ctype+1)[c]&(_P|_U|_L|_D|_SP))23#define ispunct(c) ((_ctype+1)[c]&(_P))24#define isspace(c) ((_ctype+1)[c]&(_S))25#define isupper(c) ((_ctype+1)[c]&(_U))26#define isxdigit(c) ((_ctype+1)[c]&(_D|_X))27

28#define isascii(c) (((unsigned) c)<=0x7f)29#define toascii(c) (((unsigned) c)&0x7f)30

31#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp-('A'-'a'):_ctmp)32#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp-('a'-'A'):_ctmp)33

34#endif35

1/*

2  *  linux/lib/ctype.c

3  *

4  *  (C) 1991  Linus Torvalds

5  */6

7#include8

9char _ctmp;10unsigned char _ctype[] = {0x00,/* EOF */11_C,_C,_C,_C,_C,_C,_C,_C,/* 0-7 */12_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,/* 8-15 */13_C,_C,_C,_C,_C,_C,_C,_C,/* 16-23 */14_C,_C,_C,_C,_C,_C,_C,_C,/* 24-31 */15_S|_SP,_P,_P,_P,_P,_P,_P,_P,/* 32-39 */16_P,_P,_P,_P,_P,_P,_P,_P,/* 40-47 */17_D,_D,_D,_D,_D,_D,_D,_D,/* 48-55 */18_D,_D,_P,_P,_P,_P,_P,_P,/* 56-63 */19_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,/* 64-71 */20_U,_U,_U,_U,_U,_U,_U,_U,/* 72-79 */21_U,_U,_U,_U,_U,_U,_U,_U,/* 80-87 */22_U,_U,_U,_P,_P,_P,_P,_P,/* 88-95 */23_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,/* 96-103 */24_L,_L,_L,_L,_L,_L,_L,_L,/* 104-111 */25_L,_L,_L,_L,_L,_L,_L,_L,/* 112-119 */26_L,_L,_L,_P,_P,_P,_P,_C,/* 120-127 */27 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 128-143 */28 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 144-159 */29 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 160-175 */30 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 176-191 */31 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 192-207 */32 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 208-223 */33 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 224-239 */34 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};/* 240-255 */35

36

此一段代码一看便知高下。^_^

我不认为C#的构架师是个笨笨,决计做不出来一个用大家反复调用的底层API函数还不及一段用户组合代码效率高的蠢事来,所以我认为“Char.IsNumber(str,i)的效率不如(r[i]'9')”绝对是个谬论!

-------------

乾坤一笑 写于2005年1月19日  转载请标明出处和原文链接

--------------------next---------------------

经过刚刚实际测试,VC++6.0&win2k编译环境下,编译器自动去除了inline前缀。所以改用宏的方法测试,得到结果如下。

#define isdigit(c) ((c)>='0'&&(c)

10: bool a=isdigit(c);

0040103C movsx eax,byte ptr [ebp-4]

00401040 cmp eax,30h

00401043 jl main+37h (00401057)

00401045 movsx ecx,byte ptr [ebp-4]

00401049 cmp ecx,39h

0040104C jge main+37h (00401057)

0040104E mov dword ptr [ebp-0Ch],1

00401055 jmp main+3Eh (0040105e)

00401057 mov dword ptr [ebp-0Ch],0

0040105E mov dl,byte ptr [ebp-0Ch]

00401061 mov byte ptr [ebp-8],dl

#define isdigit(c) ((_ctype+1)[c]&(_D))

29: bool a=isdigit(c);

0040103C movsx eax,byte ptr [ebp-4]

00401040 xor ecx,ecx

00401042 mov cl,byte ptr _ctype+1 (00422301)[eax]

00401048 and ecx,4

0040104B neg ecx

0040104D sbb ecx,ecx

0040104F neg ecx

00401051 mov byte ptr [ebp-8],cl

总共节省了三条指令。

实际如果精简代码,则可以达到九条指令的状态,大致如下:

#define isdigit(c) ((c)>='0'&&(c)

10: bool a=isdigit(c);

0040103C movsx eax,byte ptr [ebp-4]

00401040 cmp eax,30h

00401043 jl main+37h (00401057)

00401049 cmp eax,39h

0040104C jge main+37h (00401057)

0040104E mov dl,1

00401055 jmp main+3Eh (0040105e)

00401057 mov dl,0

00401061 mov byte ptr [ebp-8],dl

可以看出,两者效率的差异仅仅在一两条指令上,仅仅是编写小型程序并不值得。不过如果是大规模定义此类宏,又有很多非连续的(例如Hex)。那么后者显然值得这些代价。

--------------------next---------------------

楼主,我是《判断一个字符串是否全是数字的多种方法及其性能比较(C#实现)》一文的作者,先不说我那篇文章的水平怎么样(其实已经遭到了很多批评),我但就你这篇文章谈一下看法。

首先,C#不是C,而楼主却把两者混为一潭。既然楼主承认“我对C#实现理解不深”,却又怎么敢由“C中诸如isdigit(c)、isalpha(c)之类函数的实现”来推断““Char.IsNumber(str,i)的效率不如(r[i]'9')”绝对是个谬论!”呢?你怎么知道Char.IsNumber(str,i)是通过调用isdigit(char c)来写的呢?你的猜测错了,根本就不是。我通过Reflactor对Framework进行了反编译,得到了Char.IsNumber的实现(用微软提供的ildasm可以得到IL的代码,结论是一样的):

这是Char.IsNumber(string,int)的实现:

public static bool IsNumber(string s, int index)

{

if (s == null)

{

throw new ArgumentNullException("s");

}

if (index >= s.Length)

{

throw new ArgumentOutOfRangeException("index");

}

return char.IsNumber(s[index]);

}

被调用的char.IsNumber(char)实现如下:

public static bool IsNumber(char c)

{

return CharacterInfo.IsNumber(c);

}

继续追踪,CharacterInfo.IsNumber(c)的实现:

public static bool IsNumber(char ch)

{

UnicodeCategory category1 = CharacterInfo.GetUnicodeCategory(ch);

if ((category1 != UnicodeCategory.DecimalDigitNumber) && (category1 != UnicodeCategory.LetterNumber))

{

return (category1 == UnicodeCategory.OtherNumber);

}

return true;

}

继续,CharacterInfo.GetUnicodeCategory(ch)的实现:

public static UnicodeCategory GetUnicodeCategory(char ch)

{

return CharacterInfo.InternalGetUnicodeCategory(ch);

}

还有,CharacterInfo.InternalGetUnicodeCategory(ch)的实现:

internal static unsafe UnicodeCategory InternalGetUnicodeCategory(char ch)

{

byte num1 = CharacterInfo.m_pDataTable[ch >> 8];

ushort num2 = CharacterInfo.m_pLevel2WordOffset[(num1 << 4) + ((ch >> 4) & '\x000f')];

byte num3 = CharacterInfo.m_pDataTable[num2 + (ch & '\x000f')];

return (UnicodeCategory) num3;

}

好了,终于结束了。一个Char.IsNumber(str,i)就是通过上面的一系列调用来实现的,你说效率如何?如果不信可以自己去验证。

Char.IsNumber(str,i)判断的是Unicode字符,而不仅仅是ASCII字符,我在你批判的那篇文章中也提到了,Char.IsNumber(str,i)可以判断全角的1,所以调用是麻烦了一些,不过功能是增加了。可见,楼主的批判是毫无道理的。

--------------------next---------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值