最近CoolShell博主作了一个颇有意思的在线puzzle,这些谜题颇有趣同时也有必定的难度。因为水平有限,我并无通关,我以为这些题仍是很值得一作的,从中能够学到不少东西。html
例如其中的第二题:shell
题目中给出了一个键盘和一行看不懂的字符串。咱们发现这个键盘的键盘布局和如今通用的键盘(QWERTY键盘)不同,它叫作Dvorak键盘。这里就很少做解释了,详细的能够去Google。键盘图片明显在提示咱们:要经过两种键盘的布局映射,将给出的字符串转换成QWERTY键盘下的输出。固然,你能够本身一对一写出来,不过在线转换工具更方便。数组
macb() ? lpcbyu(&gbcq/_\021%ocq\012\0_=w(gbcq)/_dak._=}_ugb_[0q60)s+转换以后获得:
main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}这是1987年 国际C语言混乱代码大赛(The International Obfuscated C Code Contest, IOCCC)一等奖的获奖代码,由贝尔实验室的David Korn提交。固然平时咱们不会写出这么复杂难懂的代码,可是分析这样的代码却能够扩展咱们的知识。
int main() { /* unix被编译器内定为一个宏 * 至关于#define unix 1 */ printf("unix=%d\n", unix); /* =1 */ /* 打印字符串"un",由于"fun"是个字符数组 * "fun"+1至关于字符指针右移,指向"un" */ printf("%s\n","fun"+1); /* "have"是个字符数组,"have"[1]即字符a * 输出97,即第二个字符'a'的ASCII值。*/ printf("%d\n", "have"[1]); printf("%d\n", 'a'); /* 在C语言中,x[1] = 1[x] */ printf("%d\n", (1)["have"]); /* 97 - 96 = 0x61 - 0x60 = 1 */ printf("%d\n", (1)["have"] - 0x60); /* 因此 "fun"+((1)["have"]-0x60) 至关于"fun"+1,输出"un" */ printf("%s\n", "fun" + ((1)["have"] - 0x60)); /* 将其中的1用unix代替 */ printf("%s\n", (unix)["have"]+"fun"-0x60); /* 以上为后半部分 = "un" */ /* 下面两个都输出"bcde", 由于指针都是从'b'开始 */ printf("%s\n", "abcde" + 1); printf("%s\n", &"abcde"[1]); /* &"abcde"[1] == &(1)["abcde"] 输出同样 */ printf("%s\n", &(1)["abcde"]); /* 1用unix代替 */ printf("%s\n", &unix["abcde"]); /* 下面输出"%six" 并换行 */ printf("%s", &"?%six\n"[1]); /* 注意: \012 = 0x0a = \n, 第一个字符 \021 被跳过 \0 是空字符 */ /* 一样输出"%six" 并换行 */ printf("%s", &"\021%six\012\0"[1]); /* 至关于这样 */ printf("%s", &unix["\021%six\012\0"]); /* 把字符串"%six\n"看成格式,输出"ABix" */ printf(&unix["\021%six\012\0"], "AB"); /* 至关于这样 */ printf("%six\n", "AB"); /* 因此下面的能够输出"unix" */ printf("%six\n", (unix)["have"]+"fun"-0x60); /* 至此,问题解决!!!输出"unix" */ printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60); return 0; }
这段代码主要用到了x[a]和指针运算的一些知识,相信上面的步骤和注释已经很清楚了,最终结果就是输出unix
。工具