看看我对一段怪异程序的分析(我头晕了整整两百圈!)
这是源程序main(v,c)char**c;{for(v="hello,world!\n";
(!!c)[*c]&&(v--||--c&&execlp(*c,*c,c[!!c]+
!!c,!c));**c=!c)write(!!*c,*c,!!**c);}
----------1985年 HP Jack Applin 所写.
以下是我的分析
请不要小看这段程序,我研究了半天终于看出点名堂了,不过看的头疼不想再往下看了,我把思路写出来,如果谁愿意去研究只要有耐心可以得出结果的。
首先把程序整理一下
代码:
main(v,c)
char**c;
{
for(v[c++] = "hello, world!\n";(!!c)[*c] && (v-- || --c && execlp(*c, *c, c[!!c]+ !!c,!c)); **c = !c)
write(!!*c,*c,!!**c);
}
下面我把主要的给讲一下让大家自己去思考
首先注意第一个地方
v
其实v可以写成这种形式(c++),如果忽略++其实就是c,这样不知道能不能理解了,其实种形式用下面这个例子就好理解了
char *argv[] = {"zhang", "xin", "hua"};
这里可以先考虑argv,这个我想就不用我解释了吧,学过C的人应该都明白这是什么意思,明白了argv就可以把他改成0形式,也就是说argv 和0是等价的,这又如何理解呢,我在举个简单的例子,可以考虑100+0和0+100,是不是应该恍然大悟了?这就是问题的关键所在,同理100+2==2+100这是在也简单不过的等式了。好了这里我就不罗嗦留给大家自己去思考了。
再考虑下面重点
(!!c)[*c]
这里其实和上边大同小异只不过有点弯需要转过来,首先是(!!c)这里很容易迷惑人,其实只要c不为空,(!!c)的结果就是1,也就是说(!!c)[*c]可以写成1[*c]的形式看懂了上边的这也就不难理解了,只不过这里的*c指向了下级指针,而1[*c]其实就是取字符串的第二个字符,如果字符串的内容为空,那么就可以退出for循环了。好了接着往下看
execlp(*c, *c, c[!!c]+ !!c,!c));
这才是程序的精华所在,也是最为复杂的地方,其实这里我也只是分析了这个语句的作用,这个语句的基本作用就是递归调用上面的这个程序,至于为什么会递归调用就留给大家自己去思考吧,因为思考量太大我也没有耐心再往下想了,还是留给大家去考虑吧至于最后一句写函数就不用我说了吧,其实就是朝屏幕上打印字符串,至于到底打印什么字符串也留给大家自己去思考吧
如果想考虑这段程序还要考虑下面的问题
char *str[] = {"zhang", "xin", "hua"};
0 = "hello";
printf("%s\n", str);
想想结果是什么 今天早上起来又有了精神头,继续把这段程序给分析完了,下面是我对这断程序的改进和简化
代码:
#include <stdio.h>
#include <unistd.h>
main(int v, char **c)
{
char hello[] = "hello world!\n\n";
for(v[c] = hello; 1[*(c+1)]&&(v--||execlp(*c, *c, c[1]+1, NULL)); 0[*(c+1)] = 0)
write(1,0[(c+1)], 1);
}
在LINUX下用GCC3.2编译通过,别看这断小程序折腾的我不轻,有兴趣的朋友琢磨琢磨,呵呵 这是我分解过的程序
hello(int argc, char *argv[])
{
char hello[] = "hello world!\n ";
char *c = *(argv + 1) + 1;
argv[argc] = hello;
while(*c)
{
if(argc--)
write(1, *(argv+1), 1);
else {
execlp(*argv, *argv, *(argv+1) + 1, NULL);
break;
}
**(argv+1) = 0;
}
}
main(int argc, char *argv[])
{
char *str[argc+1];
memcpy(str, argv, sizeof(str)-4); /*防址缓冲区溢出产生异常*/
hello(argc, str);
}
强啊,我已经晕死,我要休息。 :cry:
页:
[1]