1987年國際C語言混亂代碼大賽獲獎的一行代碼

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

相關文章
相關標籤/搜索