数组的引用

main() {printf(&unix["\021%six\012\0"], (unix)["have"] + "fun" - 0x60);}

这个是1987年C语言混乱代码大赛获奖作品。

汗。。这个代码比我年纪还大。。

时至今日,这个代码依然有分析的价值。

这个代码中使用了C里面很细微地一个技巧,就是数组引用的不同方式。

我们通常对数组元素进行引用,一般都是通过a[i]或是*(a+i),明白这个技巧,其中也涉及到数组与指针的区别。

 

对于底层编辑器而言,是没有数组的概念的,它对元素的获取是通过基地址加上相应的偏移量来完成的。

尽管在编译阶段,数组与指针存在着这样或是那样的差别,但是执行到底层物理设备上时,就只有地址和偏移量两个信息了。

我们使用a[i]的形式,就是为了传递这两个信息,[]就好像我们平时运算中的加好,表示a的地址加上i个偏移量。如同数学中交换律一样,a+b与b+a并没有什么不同,同样a[i]与i[a]也没有什么不同,二者表达的一个信息,只不过在大多数教科书中都使用了a[i]的形式,更为大众所接受。然而,这些教科书却没有介绍i[a]的引用方式,导致许多人一直没有意识到这种引用方式。

 

另外在unix系统中,gcc编译器默认设置了unix宏 #define unix 1;可以使用cpp -dM /dev/null 命令查看预定义的宏,更多宏查看还要google了。

C语言对转义的规定 /ddd 为1~3位八进制数所代表的字符 /xhh表示1~2位16进制数所代表的字符,故\021表示ASCII值为十进制17的字符;\012表示换行符;\0就是字符串结束符

知道了以上信息,就可以对上面的代码进行分析了,开头的代码可以转换为

main()

{

    printf(&1["\021%six\012\0"], 1["have"]+"fun" - 0x60);

}

&1["\021%six\012\0"]从该字符串数组的第一个位置开始(注意从0开始)即“%six”,即跨过前面的\021,1["have"]即代表字符‘a’, ascii码为0x61,该代码会优先与0x60计算,即为+1,

''fun"+1即字符串“un”, 从printf指定的位置打印,即字符串“unix”。

 

你可能感兴趣的:(数组的引用)