小議國際C語言混亂代碼大賽——附87年一行的代碼分析

一年前的這個季節看的時候,網上還是停留着06年的信息,還以爲就此結束了,今天突然在CSDN首頁看到居然更新兩期了,圍觀下大牛們的傑作。

雖然在現實中,我們不可能寫出那樣的代碼,其主要的原因是不方便閱讀,而且難以維護,但一行代碼中可以學習的東西可能比我們翻半天書的還多,比如下的一行代碼就能學到平時很難學到的東西:

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

這行代碼是1987年 貝爾實驗室的 David Korn 提交了這個獲獎作品。

當然我們平時寫作是用不到這麼高深的東西,但經過如下分解後,這些知識點我們都是否能掌握呢?

如果以上代碼在windows平臺是不能直接運行的,可以再定義一下:

#define unix 1


在C語言中,數組的引用除了我們常用的 array[num],還可以是num[array],兩者是相同。 

所以(unix)["have"] 等於"have"[unix],前面unix定義爲1,這裏的結果就是have中下標爲1的那個字符a。

針對這樣的式子:"a" + "fun" - 0x60,再作一次變換,0x61-0x60+"fun",加減交換,小學就學過的,不用解釋了吧,十六進制0x61 = 十進制97,正好是小寫字母a的ASCII碼。

上面式子自然變成了0x01+"fun",一個字符串地址加上一位後會是什麼樣的呢?這樣還不明白的話,把fun當成指針裏存的數據來是不是容易理解了呢,如*prt++後的結果“un”,這樣就更容易明白了吧。

\012 是ASCII碼裏的換頁.功能與\n相同。

再前面一個%s,打印字符串不作解釋。

上面已經說到 array[num]等價num[array]

&unix["\021%siz\012\0"], 再簡化一下,&1["\021%siz\n\0"],這裏需要把\021處理成一個字符,ASCII碼裏021是什麼也不重要了,我們只把這個轉義字符處理成一個就行了,所以這個串理解爲:

"\021%siz\012\0" [1]等於"\021%siz\n\0" [1]等於"%siz\n\0"

整個語句就化解爲:printf("%siz\n\0","un");其中\0是一個(空),已經不重要了,分析到這裏,應該明白這個語句輸出的是什麼了吧!

You Got It:uniz

分析了這麼多,現在明白了,其實原理也是那麼簡單,當我們第一眼沒看出來結果的時候,我們是不是應該覺得有必要複習一下了呢?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章