編譯簡單的 C 程式
(HelloWorld,捕捉錯誤,編譯多個源檔案)
C 語言經典的入門例子是
HelloWorld,
#include <stdio.h>
int main(void)
{
printf("Hello,world!\n");
return 0;
}
我們假定該代碼存為檔案‘hello.c’。要用
gcc
編譯該檔案,使用下面的命令:
$ gcc -g-Wall hello.c -o hello
該命令將檔案‘hello.c’中的代碼編譯為機器碼並儲存在可執行檔 ‘hello’中。機器碼的檔案名稱是通過
-o
選項指定的。該選項通常作為命令列中的最後一個參數。如果被省略,輸出檔案預設為 ‘a.out’。
注意到如果目前的目錄中與可執行檔重名的檔案已經存在,它將被覆蓋。
選項
-Wall
開啟編譯器幾乎所有常用的警告──強烈建議你始終使用該選項。編譯器有很多其他的警告選項,但
-Wall
是最常用的。預設情況下GCC
不會產生任何警告資訊。當編寫 C
或 C++
程式時編譯器警告非常有助於檢測程式存在的問題。
注意如果有用到math.h庫等非gcc預設調用的標準庫,請使用-lm參數
本例中,編譯器使用了
-Wall
選項而沒產生任何警告,因為樣本程式是完全合法的。
選項 ""-g""
表示在產生的目標檔案中帶調試資訊,調試資訊可以在程式異常中止產生core後,協助分析錯誤產生的源頭,包括產生錯誤的檔案名稱和行號等非常多有用的資訊。
要運行該程式,輸入可執行檔的路徑如下:
$./hello
Hello, world!
這將可執行檔載入記憶體,並使 CPU 開始執行其包含的指令。 路徑
./
指代目前的目錄,因此
./hello
載入並執行目前的目錄下的可執行檔 ‘hello’。
捕捉錯誤
如上所述,當用 C 或 C++
編程時,編譯器警告是非常重要的助手。為了說明這一點,下面的例子包含一個微妙的錯誤:為一個整數值錯誤地指定了一浮點數控制符‘%f’。
#include <stdio.h>
int main (void)
{
printf("Two plus twois %f\n",
4);
return0;
}
一眼看去該錯誤並不明顯,但是它可被編譯器捕捉到,只要啟用了警告選項
-Wall。
編譯上面的程式‘bad.c’,將得到如下的訊息:
$ gcc-Wall bad.c -o bad
main.c: 在函數‘main’中:
main.c:5: 警告: 格式‘%f’需要類型‘double’,但實參 2 的類型為‘int’
這表明檔案 ‘bad.c’第 6 行中的格式字串用法不正確。GCC 的訊息總是具有下面的格式
檔案名稱:行號:訊息。編譯器對錯誤與警告區別對待,前者將阻止編譯,後者表明可能存在的問題但並不阻止程式編譯。
本例中,對整數值來說,正確的格式控制符應該是
%d。
如果不啟用
-Wall,程式表面看起來編譯正常,但是會產生不正確的結果:
$ gccbad.c -o bad
$ ./bad
Two plus two is 0.000000
顯而易見,開發程式時不檢查警告是非常危險的。如果有函數使用不當,將可能導致程式崩潰或產生錯誤的結果。開啟編譯器警告選項
-Wall
可捕捉 C
編程時的多數常見錯誤。
編譯多個源檔案
一個來源程式可以分成幾個檔案。這樣便於編輯與理解,尤其是程式非常大的時候。這也使各部分獨立編譯成為可能。
下面的例子中我們將程式
HelloWorld
分割成 3
個檔案:‘hello.c’,‘hello_fn.c’和標頭檔‘hello.h’。
這是第一個檔案,即主程式‘hello.c’:
#include "hello.h"
int main(void)
{
hello ("world");
return0;
}
在先前例子的‘hello.c’中,我們調用的是庫函數
printf,本例中我們用一個定義在檔案‘hello_fn.c’中的函數
hello
取代它。
主程式中包含有標頭檔‘hello.h’,該標頭檔包含函數
hello
的聲明。我們不需要在‘hello.c’檔案中包含系統標頭檔‘stdio.h’來聲明函數
printf,因為‘hello.c’沒有直接調用
printf。
這是第二個檔案‘hello.h’,檔案‘hello.h’中的聲明只用了一行就指定了函數
hello
的原型。
void hello
(const
char * name);
函數
hello
的定義在第三個檔案‘hello_fn.c’中:
#include <stdio.h>
#include "hello.h"
void hello (const
char * name)
{
printf("Hello, %s!\n",name);
}
語句
#include"FILE.h"
與
#include <FILE.h>
有所不同:前者在搜尋系統標頭檔目錄之前將先在目前的目錄中搜尋檔案‘FILE.h’,後者只搜尋系統標頭檔而不查看目前的目錄。
要用gcc編譯以上源檔案,使用下面的命令:
$ gcc-Wall hello.c hello_fn.c -o newhello
本例中,我們使用選項
-o
為可執行檔指定了一個不同的名字
newhello。注意到標頭檔‘hello.h’並未在命令列中指定。源檔案中的的
#include "hello.h"
指示符使得編譯器自動將其包含到合適的位置。
要運行本程式,輸入可執行檔的路徑名:
$./newhello
Hello, world!
來源程式各部分被編譯為單一的可執行檔,它與我們先前的例子產生的結果相同。