前两天在园子里面分析了一段混乱代码,不知道为什么: 诺贝尔大侠说我的结论是放屁。
可能有两个原因:
1、也许是因为我的分析不对,
2、也许是因为我在里面的一句话“英语比汉语更适合描述科技”。
如果是因为第1个原因,那么我只能说诺大侠是否可以到各著名的教程中进行求证,或者按照
我的分析运行一下代码。(如果在win下运行代码,不能得到结果,那么请注意返回看看我的分析)。
如果是因为第二个原因, 我只能说这个只是我个人的感觉,并且这句话也不是我说的, 不要和我
说爱国。就像曾经申奥的时候我不去看一样,我同学说我不爱国,我没有和他争辩,我给他的回答是:
如果现在发生第三次世界大战,我会和我们其他的同胞一起拿起枪械战斗在最前线,来保卫自己的国家。
就像dota里面的巨魔战将,他是为战斗而生的,因为战斗所以他存在,因为存在所以他战斗。
不多说了,下面首先来看看这次贴出来的代码:
#include<stdio.h>
#include<ctype.h>
#define w printf
#define p while
#define t(s) (W=T(s))
char*X,*B,*L,I[99];M,W,V;D(){W==9?(w("`%.*s' is ",V,X),t(0)):W==40?(t(0),D(),t(41)):W==42?(t(0),D(),w("ptr to ")):0;p(W==40?(t(0),w("func returning "),t(41)):W==91?(t(0)==32?(w("array[0..%d] of ",atoi(X)-1),t(0)):w("array of "),t(93)):0);}main(){p(w("input: "),B=gets(I))if(t(0)==9)L=X,M=V,t(0),D(),w("%.*s.\n\n",M,L);}T(s){if(!s||s==W){p(*B==9||*B==32)B++;X=B;V=0;if(W=isalpha(*B)?9:isdigit(*B)?32:*B++)if(W<33)p(isalnum(*B))B++,V++;}return W;}
代码的作用是:
获取用户输入的函数原型,并输出函数的返回值,不对函数参数进行检查。
获取用户输入的变量定义,并输出变量的定义类型
并且输入的一行不能分成三组及以上的字符串序列
例如输入:
unsigned int b
时不能得到正确的答案。
例如输入:
int getchar(FILE *)
则输出:
'getchar' is func returnning int
这段代码和上次分析的代码来比较,明显比上次的复杂,还是按照曾经用过的步骤进行分析:
第一步: 缩排
第二步:替换宏
第三步:分析代码
第四步:测试输出。
下面按部就班的来分析:
第一步:缩排
#include<stdio.h>
#include<ctype.h>
#define w printf
#define p while
#define t(s) (W=T(s))
char *X,*B,*L,I[99];
M,W,V;
D()
{
W==9? ( w("`%.*s' is ",V,X),t(0)): W==40?(t(0),D(),t(41)): W==42?(t(0),D(),w("ptr to ")): 0;
p( W==40? (t(0),w("func returning "),t(41)): W==91? (t(0)==32? (w("array[0..%d] of ",atoi(X)-1),t(0)): w("array of "),t(93)):0
);
}
main()
{
p( w("input: "),B=gets(I))
if(t(0)==9)
L=X,M=V,t(0), D(), w("%.*s.\n\n",M,L);
}
T(s)
{
if(!s||s==W)
{
p(*B==9||*B==32)
B++;
X=B;
V=0;
if(W=isalpha(*B)? 9:isdigit(*B) ? 32:*B++)
if(W<33)
p(isalnum(*B))
B++,V++;
}
return W;
}
第二步: 进行宏替换
这一步不但要做一些宏替换,还要补全一些定义,因为根据K&R和ANSI C规范有些地方存在出入,现在
分析的代码主要是根据K&R规范编写的。所以有些地方在ANSI C标准的编译器里面不能完成编译过程。
#include<stdio.h>
#include<ctype.h>
#define w printf
#define p while
#define t(s) (W=T(s))
char *X,*B,*L,I[99];
int M,W,V; //这里添加int类型定义,在K&R编译器里面,省略类型的变量定义默认为int型。
D()
{
W==9?(printf("`%.*s' is ",V,X),t(0)): W==40?(t(0),D(),t(41)): W==42?(t(0),D(),printf("ptr to ")):0;
while( W==40 ? (t(0),printf("func returning "),t(41)): W==91 ? ( t(0)==32 ? (printf("array[0..%d] of ",atoi(X)-1),t(0)): printf("array of "),t(93) ) :0
);
}
main()
{
while( printf("input: "),B=gets(I))
if(t(0)==9)
L=X,M=V,t(0), D(), printf("%.*s.\n\n",M,L);
}
T(int s) //这里添加int类型定义,在K&R编译器里面,省略类型的变量定义默认为int型。
{
if(!s||s==W)
{
while(*B==9||*B==32)
B++;
X=B;
V=0;
if(W=isalpha(*B)? 9 :isdigit(*B) ? 32:*B++)
if(W<33)
while(isalnum(*B))
B++,V++;
}
return W;
}
第三步:代码分析
首先将存在的用十进制的ASCII码表示的字符分析出来
#include<stdio.h>
#include<ctype.h>
#define w printf
#define p while
#define t(s) (W=T(s))
char *X,*B,*L,I[99];
int M,W,V;
D()
{
// ( 的ASCII码值 = 40
// ) 的ASCII码值 = 41
// * 的ASCII码值 = 42
// [ 的ASCII码值 = 91
// ] 的ASCII码值 = 93
W==9?(printf("`%.*s' is ",V,X),t(0)): W==40?(t(0),D(),t(41)): W==42?(t(0),D(),printf("ptr to ")):0;
while( W==40 ? (t(0),printf("func returning "),t(41)): W==91 ? ( t(0)==32 ? (printf("array[0..%d] of ",atoi(X)-1),t(0)): printf("array of "),t(93) ) :0
);
}
main()
{
while( printf("input: "),B=gets(I))
if((W=T(0))==9 )
if(t(0)==9)
L=X,M=V,t(0), D(), printf("%.*s.\n\n",M,L);
}
T(s)
{
if(!s||s==W)
{
//TAB制表符的ASCII码值==9
//space的ASCII码值==32
while(*B==9||*B==32)
B++;
X=B;
V=0;
if(W=isalpha(*B)? 9 :isdigit(*B) ? 32:*B++)
if(W<33)
while(isalnum(*B))
B++,V++;
}
return W;
}
接下来还需要继续分析main函数
main()
{
//gets函数的返回值是I,就是说如果不是遇到EOF,那么程序将一直执行下去
//gets函数在I后面增加一个 NUL 字符
//gets函数每次从标准输入读取时遇到换行就结束 ,通过按下Enter键产生换行字符
while( printf("input: "),B=gets(I))
//这里需要进行一下替换才能理解下面的if语句
//可以替换为
/*
if((W=T(0))==9 )
*/
if(t(0)==9) //如果输入行首字符不是换行的话那么会执行下面的语句
//首先将要输出的首地址和输出的字符长度赋值给L和M
//这里有一个特别的地方: 格式化字符串中的 * 的应用,具体可以参考
//某些较为出名的书籍。
//这里还用到了带参数宏t(s),需要再执行一次W=T(0) 这个宏,并且用T(S)函数执行
L=X,M=V,t(0), D(), printf("%.*s.\n\n",M,L);
}
接下来分析T(int s)函数:
T(s)
{
if(!s||s==W)
{
//TAB制表符的ASCII码值==9
//space的ASCII码值==32
while(*B==9||*B==32)
B++;
//将除去制表符和空格的字符串地址赋值给X
X=B;
//用V来计算非制表符和非空格字符的数量
V=0;
//如果除去制表符和空格的输入字符串后面的首字符如果是
//字母的话, W=9
//如果除去制表符和空格的输入字符串后面的首字符如果
//是数字的话,那么 W=32
//如果既不是字母也不是数字,那么W 就是字符串中取一个字符
//如果取出来的字符是 NUL的话 就不执行后面的操作
//这里要实现的就是如果输入的第一个非空白字符是字母的话就计算接下来输入的
//输入的字目和数字的个数
if(W=isalpha(*B)? 9 :isdigit(*B) ? 32:*B++)
//如果取出来的是非打印字符,那么就执行下面的操作
if(W<33)
//如果是数字或字母的话那么就一直往前走
while(isalnum(*B))
B++,V++;
}
return W;
}
通过分析可知T(s)的作用是去除输入行中的前导制表符和前导空,并且计算输入的可以作为标示符的字符个数
接下来分析D()函数
D()
{
// ( 的ASCII码值 = 40
// ) 的ASCII码值 = 41
// * 的ASCII码值 = 42
// [ 的ASCII码值 = 91
// ] 的ASCII码值 = 93
W==9?(printf("`%.*s' is ",V,X),t(0)): W==40?(t(0),D(),t(41)): W==42?(t(0),D(),printf("ptr to ")):0;
while( W==40 ? (t(0),printf("func returning "),t(41)): W==91 ? ( t(0)==32 ? (printf("array[0..%d] of ",atoi(X)-1),t(0)): printf("array of "),t(93) ) :0
);
}
为了更好的分析D()函数我们可以将 ?: 表达式用if语句进行转换:
D()
{
if(W==9)
{
(printf("`%.*s' is ",V,X),t(0));
}
else
{
if(W==40) //出现 ( 时就用t(41)
{
(t(0),D(),t(41));
}
else
{
W==42?(t(0),D(),printf("ptr to ")):0; //如果输入的字符串里面出现了 * 则说明有指针类型
}
}
while( W==40 ? (t(0),printf("func returning "),t(41)): W==91 ? ( t(0)==32 ? (printf("array[0..%d] of ",atoi(X)-1),t(0)): printf("array of "),t(93) ) :0
);
}
这样并没有完全转变好,还需要将while循环进行转换,通过前面的缩排,while循环有一个空语句循环体,可以不分析,
while循环条件语句是:
W==40 ? (t(0),printf("func returning "),t(41)): W==91 ? ( t(0)==32 ? (printf("array[0..%d] of ",atoi(X)-1),t(0)): printf("array of "),t(93) ) :0
主要分析的是条件语句, 下面分析仅是为了好理解条件语句,并没有完全按照C语法来分析:
if(W==40)
{
//如果字符是 ( 则下面的表达式作为while条件
//根据逗号表达式 实际是 t(41)作为判断条件
//判断是否为函数
(t(0),printf("func returning "),t(41))
}
else
{
//判断是否为数组类型
//如果字符是[ 则下面的表达式作为while的条件
if(W==91)
{
//根据逗号表达式规则,T(0)作为判断条件
if(t(0)==32)
(printf("array[0..%d] of ",atoi(X)-1),t(0))
else
//根据逗号表达式规则,T(93)作为判断条件
printf("array of "),t(93)
}
else
// 如果不是 ( 和 [ 则循环结束
0;
}
这里进行分析仅是起一个抛砖引玉的作用。
从这里可以看出作者喜欢用 ? : 来进行操作,并且用这个操作实现了负责的功能。
C语言的东西实在是太负责和不可思议了,经常能 "于细微处见真章"。
今天发现一个问题, 当将代码贴到编辑器里面后,就不能在里面进行编辑了,如果编辑
就会出现很多 </br> <br>这样的html代码。
我用的浏览器是Firefox 3.6不知道是什么原因, 所以对文章进行重新编辑。