【在主畫面加入捷徑】
       
【選擇語系】
繁中 简中

[C 語言] 程式設計教學:如何在終端機中使用 GCC (或 Clang)

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email
【贊助商連結】

    本文會選 GCC 而非其他 C 編譯器是因為 GCC 在 GNU/Linux 等類 Unix 系統上具有代表性。如果讀者使用 Clang,因 Clang 參數刻意相容於 GCC,仍然可以參考本文來學習 Clang;而且 Clang 的錯誤訊息比 GCC 友善,倒也不失為一個學習 C 語言的替代工具。

    對於初學者,先記住以下流程即可:

    $ gcc -o hello hello.c
    $ ./hello
    Hello World

    本文的目的是整理一些常見的 GCC (或 Clang) 的使用方式,初學者覺得難以吸收或用不到的話可以先跳過沒關係。

    檢查 GCC (或 Clang) 的版本

    參考以下指令:

    $ gcc --version
    gcc (Ubuntu 4.8.4-2ubuntu1~14.04.4) 4.8.4
    Copyright (C) 2013 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    在線上討論區討論問題時,可以貼上自己所用的 C 編譯器的版本,偶爾會從中得到一些有用的回應。

    開啟警告訊息

    -Wall 會開啟所有警告,一開始練習時建議開啟,可以從錯誤訊息中學習。除此之外,也可以開啟 -Wextra,有更多的錯誤訊息。參考以下指令:

    $ gcc -Wall -Wextra -g -o file file.c

    -Werror 會將警告訊息轉為錯誤,初期對練習寫 C 程式會有一些幫助。不過,GCC 有些警告訊息其實不會造成實質的影響,筆者會去看 GCC 的警告訊息,但不會開啟這個選項。

    -pedantic 對非標準 C 的語法會出現錯誤訊息,若注重相容性可開啟此選項。

    開啟除錯相關資訊

    加入 -g 可以在編譯出來的程式中加上除錯相關的資訊,如果要對編譯出來的執行檔使用 GDB 等除錯器 (debugger) 除錯時就需要在編譯時加入此參數。由於這個參數對程式運行本身沒有幫助,最後要發布實際要上線的程式時,建議關掉這項參數重新編譯一次。

    開啟剖析 (Profiling) 相關資訊

    加入 -pg 可在編譯時加入 gprof 程式可用的訊息,可和 -g 併用。由於在程式中加入剖析相關資訊會影響程式運行效能,程式要正式上線時要關掉這個選項重新編譯。

    選擇編譯最佳化策略

    GCC 有許多和最佳化相關的參數,這些參數相當複雜。為了簡化最佳化的過程,GCC 提供一些預先配置好的「套餐」。常見的選項如下:

    • -O0 (關閉最佳化)
    • -O1
    • -O2
    • -O3
    • -Os (空間最佳化)

    -02 是保守但可用的最佳化策略,要效能可試著用 -O3 來編譯程式,除此之外,還有一些細部的選項可以把玩。一開始學習時不太需要耗費過多時間在這裡。

    編譯多個檔案

    初學時會把所有的程式碼寫在同一個檔案中,但實務上的程式會拆成多個檔案。可參考以下指令:

    $ gcc -Wall -g -o program main.c file_a.c file_b.c file_c.c

    相關的標頭檔 (header) 要預先撰寫,於後文會再說明。

    指定 C 標準 (C Standard) 的版本

    參考以下指令:

    $ gcc -Wall -g -std=c99 -o program main.c

    GCC 中常見的 C 語言標準:

    • c89c90-ansi:即 ANSI C
    • c99
    • c11
    • c17c18:不要和 C++17 搞混,這是一個小的 C 標準修正版
    • gnu89gnu90c90 加上 GNU C extension
    • gnu99c99 加上 GNU C extension
    • gnu11c11 加上 GNU C extension
    • gnu17c17 加上 GNU C extension

    一開始建議使用 c90c99,需要較新的 C 標準才逐漸加入,以維持相容性。GNU C extension 不是 C 標準的語法,除非很確定該專案只會用到 GCC 來編譯,不建議任意地使用。

    加入外部函式庫

    除了一些內建的函式庫以外,編譯時要加入相關的參數。常見的例子像是 -lm (數學公式)、-lpthread (POSIX 多執行緒)、-lrt (POSIX realtime extension) 等。參考以下指令:

    $ gcc -Wall -g -o program file.c -lm

    -lm 來說,其讀法為 -l (函式庫) 加上 m (數學函式庫),其他函式庫同理可知。

    有些函式庫不是位於系統內建的位置上,則要另外加上 -I (標頭檔位置) 和 -L (函式庫位置)。參考以下指令:

    $ gcc -Wall -g -o program file.c -I/path/to/include -L/path/to/lib -lsomething

    pkg-config 是一個用來簡化編譯第三方函式庫的小工具,透過這套工具,我們不用手寫 -I-L 等參數。

    例如,我們以 pkg-config 自動產生適用於 libpng 的參數 (於 Mac 上測試):

    $ pkg-config --libs --cflags libpng
    -I/usr/local/Cellar/libpng/1.6.34/include/libpng16 -L/usr/local/Cellar/libpng/1.6.34/lib -lpng16 -lz

    編譯時將此段參數插入指令之中即可:

    $ gcc -o program file.c `pkg-config --libs --cflags libpng`

    編譯函式庫

    函式庫是 C (或 C++) 分享程式的方式,分為靜態連結 (static linking) 和動態連結 (dynamic linking);前者會將程式編入主程式中,後者則否。

    編譯靜態連結函式庫可參考以下指令:

    $ gcc -c -o something.o something.c
    $ ar rcs libsomething.a something.o

    編譯動態連結函式庫可參考以下指令:

    $ gcc -fPIC -c -o something.o something.c
    $ gcc -shared -o libsomething.so something.o

    小結

    本文所述大概僅佔 GCC 參數的一小部分,但一些冷門的參數其實也很少用,需要時再去查詢即可。如果每次都要手動輸入編譯指令其實蠻辛苦的,我們在這裡介紹 GNU Make,這是一個流程自動化軟體,可減少手動輸入指令的負擔。

    【贊助商連結】
    【贊助商連結】
    【分類瀏覽】