深入探討 C 語言

6
深入探討C語言 假設你在面試求職者是否了解C語言,於是問了第一個問題: ================================================= 此程式碼會有什麼結果? ================================================= 底下是兩位求職者的回答, 假求職者: 需要加上#include <stdio.h>return 0,這樣才可通過編譯(compile)與連結(link)執行時會在螢幕上輸出42真求職者: 可能需要加上含有printf()宣告的 #include <stdio.h>,這樣才可通過編譯(compile)連結(link),執行時會將數字42加上換行寫到標準輸出串流。 此程式碼會無法通過C++編譯器,因為C++語言需要宣告所有的函式。 然而C編譯器會建立隱藏的printf()函式宣告,並將此程式碼編譯成object file,與標準函 式庫連結時,就會找到printf()函式的定義,於是上述程式碼就可編譯、連結與執行,但可 能會看到一個警告。 C99C++98,程式離開(exit value)定義為執行環境的成功回傳,但舊版的C,例 ANSI CK&R,在此程式碼中,程式的離開會成為未定義的垃圾(garbage value) 。此程式碼的離開應該會是3,因為printf()會回傳3→為寫到標準輸出的字元個數。 提到C語言標準,那此程式碼的進入點要寫成int main(void),還有容許我吹毛求疵一下, C語言標準程式碼需要以換行為結尾。 此程式碼的編譯與執行情況

Transcript of 深入探討 C 語言

Page 1: 深入探討 C 語言

深入探討C語言  假設你在面試求職者是否了解C語言,於是問了第一個問題: =================================================       此程式碼會有什麼結果? =================================================  底下是兩位求職者的回答,  假求職者: 「 需要加上#include <stdio.h>和 return 0,這樣才可通過編譯(compile)與連結(link),執行時會在螢幕上輸出42。 」  真求職者: 「 可能需要加上含有printf()宣告的 #include <stdio.h>,這樣才可通過編譯(compile)與連結(link),執行時會將數字42加上換行寫到標準輸出串流。  此程式碼會無法通過C++編譯器,因為C++語言需要宣告所有的函式。 然而C編譯器會建立隱藏的printf()函式宣告,並將此程式碼編譯成object file,與標準函式庫連結時,就會找到printf()函式的定義,於是上述程式碼就可編譯、連結與執行,但可能會看到一個警告。  在C99與C++98,程式離開值(exit value)定義為執行環境的成功回傳值,但舊版的C,例如ANSI C與 K&R,在此程式碼中,程式的離開值會成為未定義的垃圾值(garbage value)。此程式碼的離開值應該會是3,因為printf()會回傳3→為寫到標準輸出的字元個數。  提到C語言標準,那此程式碼的進入點要寫成int main(void),還有容許我吹毛求疵一下,C語言標準說程式碼需要以換行為結尾。 」  此程式碼的編譯與執行情況 

       

    

Page 2: 深入探討 C 語言

第二個問題: =================================================                   此程式碼會有什麼結果? =================================================  假求職者: 「 這未定義吧?會得到垃圾值(garbage value)? 」  真求職者: 「 不,會得到1、2、3。因為語言規格說靜態變數的初始值為0。 」  此程式碼的編譯與執行情況  

            

    

Page 3: 深入探討 C 語言

第三個問題: =================================================                    此程式碼會有什麼結果? =================================================   假求職者: 「 得到1、1、1。 」  真求職者: 「 會得到未定義的值,理論上會得到三個垃圾值,實際上自動變數(auto variables)被配置在執行堆疊裡,變數a可能會在相同的的記憶體位置,可能會得到三個連續值,但有最佳化的情況又不一樣了。  將自動變數的初始值設為0會增加函式呼叫的成本,C語言非常重視執行速度。另外在C++中,靜態變數的初始執不是0,而是設定為預設值,而基本型別剛好是0。 」  此程式碼的編譯與執行情況           

Page 4: 深入探討 C 語言

第四個問題: =================================================               此程式碼會有什麼結果? =================================================  假求職者: 「 因為a是static,初始值會是零,於是會輸出1、2、3。 」                 那此程式碼又會有什麼結果? 假求職者: 「 垃圾值、垃圾值、垃圾值。 初始值還是零嗎? 是不是跟私有(private)變數和公開(public)變數有關? 」  真求職者: 「 

Page 5: 深入探討 C 語言

會輸出1、2、3,因為此變數的初始值也是零。然而跟static不同的是連結器(linker)的可見度,此變數可在其他的編譯單元存取到,但有加static的變數,就只能在此編譯單元可見。 」   第五個問題: =================================================                         請解釋會什麼執行結果會是42。 =================================================  假求職者: 「 也許編譯器有存放變數的地方,在bar()中變數被建立了,而在foo()中會依變數a的記憶體位址去取值,如果將bar()與foo()中的變數名稱改為不一樣,結果應該就不會是42了。 」  真求職者: 「 真棒!我喜歡這題目。你要我解釋execution stack與activation frames嗎? (不用,但若是做最佳化或是使用別的編譯器又會是什麼情況?) 很多事都可能發生,不過結果不會是42。 」  剩下的請有興趣的人閱讀參考資料吧。