程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 最短的崩潰程序(C語言版)

最短的崩潰程序(C語言版)

編輯:C++入門知識

想寫個崩潰的C語言小程序,看起來是個奇怪的主意,不過在我曾經教過的一門實驗課上,這是作業之一!實際上,這是一件非常有教學意義的事情。

通常學生們要麼嘗試反向引用一個非法地址,要麼就是除0.除0會引發SIGFPE信號浮點異常)。這裡有一個小例子程序,使用除零方法來使之崩潰:

  1. int main()  
  2. {  
  3.     return 1/0;  

我們也可以刪掉return關鍵字,但是當我這麼做的時候gcc不會為這些語句生成可執行代碼,即便優化選項被disable掉了。我們還可以通過把上面的語句改成賦值語句,使上面的代碼改變一些特征:

  1. i;  
  2. int main()  
  3. {  
  4.     i=1/0;  

注意我聲明了一個沒有類型的i。這樣的代碼在C89標准裡是有效的,因為所有的聲明都有隱形的缺省類型int。在C99和其他一些C標准裡這是一個錯誤。假定我們寫的是C89代碼,那麼我們甚至可以使用隱形int來聲明main函數:

  1. i;  
  2. main()  
  3. {  
  4.     i=1/0;  

那是相當短的代碼了 — 如果我們不把用於縮進的空格計算進來,只有16個字符。然而,我們還可以做得更好!

當C程序在編譯的時候,編譯器會產生一個或更多對象文件,文件裡有對於用到的庫和全程對象函數和變量)的符號索引。然後這些對象文件會被進行鏈接,這時符號索引被地址所代替,就產生了一個可執行文件。

編譯器在一個對象文件裡提供了一個調用main函數的入口點。調用main函數意味著我們試圖執行在存儲在main函數鏈接的位置所對應地址裡的指令。

有趣的是,鏈接器對於不同對象的類型是沒有概念的,它只知道它們的地址。所以,如果我們用一個常規的全程變量替換main函數,編譯器會高興地build對象文件,因為它不關心對象main的類型是什麼;鏈接器也會高興地鏈接它,因為它只關心main函數對應的地址。

所以,考慮這個C程序:

  1. int main=0; 

這個程序會編譯成一個可執行文件,它會試圖調用地址0,而0並不是我們能夠訪問的地址,這樣我們會得到SIGSEGV信號分段錯誤)。

更正:我前面關於這個程序崩潰的原因分析是錯的。這個程序會試圖按函數方式去執行main,而這樣不會奏效,因為編譯器把它放到了不可執行的數據段。所以變量main初始化為什麼值都無所謂了。感謝Zack的糾正)

現在我們已經非常接近最小的崩潰的C程序了。我們可以利用這個技巧,配合隱形int類型,來把它進一步縮短。

  1. main=0; 

還有,C裡的全局變量都會隱形地初始化為0,所以上面的代碼就等同於:

  1. main; 

好了,現在我們得到了最短的崩潰的C程序!

補充:

Hacker News用戶femto指出,編譯和鏈接一個空文件也是可能的。我沒有發布這個是因為gcc會拒絕編譯和鏈接這樣的程序,它會要求分開編譯和鏈接的過程。

另外,要是我們再學究一點,我應該指出我這裡的“全局”變量意思是說“靜態”變量。

英文原文:llbit.se

譯文鏈接:http://blog.jobbole.com/40286/

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved