最近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
。工具