編譯簡單的 C 程序
C 語言經典的入門例子是 Hello World,下面是一示例代碼:
#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 two is %f\n", 4);
return 0;
}
一眼看去該錯誤並不明顯,但是它可被編譯器捕捉到,只要啟用了警告選項 -Wall。 編譯上面的程序‘bad.c’,將得到如下的消息:
$ gcc -Wall -o bad bad.c
main.c: 在函數‘main’中:
main.c:5: 警告: 格式‘%f’需要類型‘double’,但實參 2 的類型為‘int’
這表明文件 ‘bad.c’第 6 行中的格式字符串用法不正確。GCC 的消息總是具有下面的格式 文件名:行號:消息。編譯器對錯誤與警告區別對待,前者將阻止編譯,后者表明可能存在的問題但並不阻止程序編譯。
本例中,對整數值來說,正確的格式控制符應該是 %d。
如果不啟用 -Wall,程序表面看起來編譯正常,但是會產生不正確的結果:
$ gcc bad.c -o bad
$ ./bad
Two plus two is 0.000000
顯而易見,開發程序時不檢查警告是非常危險的。如果有函數使用不當,將可能導致程序崩潰或產生錯誤的結果。開啟編譯器警告選項 -Wall 可捕捉 C 編程時的多數常見錯誤。
編譯多個源文件
一個源程序可以分成幾個文件。這樣便於編輯與理解,尤其是程序非常大的時候。這也使各部分獨立編譯成為可能。
下面的例子中我們將程序 Hello World 分割成 3 個文件:‘hello.c’,‘hello_fn.c’和頭文件‘hello.h’。
這是主程序‘hello.c’:
#include "hello.h"
int main(void)
{
hello ("world");
return 0;
}
在先前例子的‘hello.c’中,我們調用的是庫函數 printf,本例中我們用一個定義在文件‘hello_fn.c’中的函數 hello 取代它。
主程序中包含有頭文件‘hello.h’,該頭文件包含函數 hello 的聲明。我們不需要在‘hello.c’文件中包含系統頭文件‘stdio.h’來聲明函數 printf,因為‘hello.c’沒有直接調用 printf。
文件‘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!
源程序各部分被編譯為單一的可執行文件,它與我們先前的例子產生的結果相同。
---------------------------------------
undefined reference to `sqrt' 問題
在gcc下用到數學函數,如sqrt。在gcc時要加上 -lm 參數,這樣告訴編譯器我要用到數學函數了 。
如:
gcc a.c -o a -lm