【知識點】 gcc和g++的聯絡和區別

李春港發表於2021-03-02

目前(2020-09)GCC 編譯器已經更新至 10.2版本,其功能也由最初僅能編譯 C 語言,擴增至可以編譯多種程式語言,其中就包括 C++ 。

除此之外,當下的 GCC 編譯器還支援編譯 Go、Objective-C,Objective-C ++,Fortran,Ada,D 和 BRIG(HSAIL)等程式,甚至於 GCC 6 以及之前的版本還支援編譯 Java 程式。但本教程主要講解如何使用 GCC 編譯器編譯執行 C 和 C++ 程式,因此有關其它程式語言如何使用 GCC 編譯器編譯,將不再做具體講解。

那麼,在已編輯好 C 語言或者 C++ 程式碼的前提下,如何才能呼叫 GCC 編譯器為我們編譯程式呢?很簡單,GCC 編譯器已經為我們提供了呼叫它的介面,對於 C 語言或者 C++ 程式,可以通過執行 gcc 或者 g++ 指令來呼叫 GCC 編譯器。

值得一提的是,實際使用中我們更習慣使用 gcc 指令編譯 C 語言程式,用 g++ 指令編譯 C++ 程式碼。需要強調的一點是,這並不是 gcc 和 g++ 的區別,gcc 指令也可以用來編譯 C++ 程式,同樣 g++ 指令也可以用於編譯 C 語言程式。

那麼,gcc 和 g++ 的區別是什麼呢?接下來就給讀者做詳細的講解。

實際上,只要是 GCC 支援編譯的程式程式碼,都可以使用 gcc 命令完成編譯。可以這樣理解,gcc 是 GCC 編譯器的通用編譯指令,因為根據程式檔案的字尾名,gcc 指令可以自行判斷出當前程式所用程式語言的類別,比如:

  • xxx.c:預設以編譯 C 語言程式的方式編譯此檔案;
  • xxx.cpp:預設以編譯 C++ 程式的方式編譯此檔案。
  • xxx.m:預設以編譯 Objective-C 程式的方式編譯此檔案;
  • xxx.go:預設以編譯 Go 語言程式的方式編譯此檔案;

當然,gcc 指令也為使用者提供了“手動指定代表編譯方式”的介面,即使用 -x 選項。例如,gcc -xc xxx 表示以編譯 C 語言程式碼的方式編譯 xxx 檔案;而 gcc -xc++ xxx 則表示以編譯 C++ 程式碼的方式編譯 xxx 檔案。有關 -x 選項的用法,後續會給出具體樣例。

但如果使用 g++ 指令,則無論目標檔案的字尾名是什麼,該指令都一律按照編譯 C++ 程式碼的方式編譯該檔案。也就是說,對於 .c 檔案來說,gcc 指令以 C 語言程式碼對待,而 g++ 指令會以 C++ 程式碼對待。但對於 .cpp 檔案來說,gcc 和 g++ 都會以 C++ 程式碼的方式編譯。

有讀者可能會認為,C++ 相容 C 語言,因此對於 C 語言程式來說,使用 gcc 編譯還是使用 g++ 編譯,應該沒有什麼區別,事實並非如此。嚴格來說,C++ 標準和 C 語言標準的語法要求是有區別的。舉個例子:

//位於 demo.c 檔案中
#include <stdio.h>
int main() {    
  constchar * a = "abc";     
  printStr(a);    
  return;
}

int printStr(const char* str) {
  printf(str);
}

如上所示,這是一段不規範的 C 語言程式碼。如果我們使用 gcc 指令編譯,如下所示:

[root@bogon ~]# gcc -xc demo.c   #或者直接執行 gcc demo.c
[root@bogon ~]#

可以看到,該指令的執行過程並沒有發生任何錯誤。而同樣的程式,如果我們使用 g++ 指令編譯:

[root@bogon ~]# g++ demo.c
demo.c: In function ‘int main()’:
demo.c:5: error: ‘printStr’ was not declared in this scope
demo.c:6: error: return-statement with no value, in function returning ‘int’
[root@bogon ~]# 

可以看到,GCC 編譯器發現了 3 處錯誤。顯然,C++ 標準對程式碼書寫規範的要求更加嚴格。

除此之外對於編譯執行 C++ 程式,使用 gcc 和 g++ 也是有區別的。要知道,很多 C++ 程式都會呼叫某些標準庫中現有的函式或者類物件,而單純的 gcc 命令是無法自動連結這些標準庫檔案的。舉個例子:

//demo.cpp
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string str = "C語言中文網";
    cout << str << endl;
    return 0;
}

這是一段很簡單的 C++ 程式,其通過 標頭檔案提供的 string 字串類定義了一個字串物件,隨後使用 cout 輸出流物件將其輸出。對於這段 C++ 程式碼,如果我們使用 g++ 指令編譯,如下所示:

[root@bogon ~]# g++ demo.cpp
[root@bogon ~]#

可以看到,整個編譯過程沒有報任何錯誤。但如果使用 gcc 指令:

[root@bogon ~]# gcc demo.cpp
/tmp/ccIOnwra.o: In function `main':
demo.cpp:(.text+0x13): undefined reference to `std::allocator<char>::allocator()'
#省略了諸多錯誤資訊

讀者可自行編譯,就可以看到很多報錯資訊。其根本原因就在於,該程式中使用了標準庫 提供的類物件,而 gcc 預設是無法找到它們的。

如果想使用 gcc 指令來編譯執行 C++ 程式,需要在使用 gcc 指令時,手動為其新增 -lstdc++ -shared-libgcc 選項,表示 gcc 在編譯 C++ 程式時可以連結必要的 C++ 標準庫。也就是說,我們可以這樣編譯 demo.cpp 檔案:

[root@bogon ~]# gcc -xc++ -lstdc++ -shared-libgcc demo.cpp
[root@bogon ~]#

由此,demo.cpp 就被成功的編譯了。

讀者可以這樣認為,g++ 指令就等同於gcc -xc++ -lstdc++ -shared-libgcc指令。顯然後者書寫是非常麻煩的,大多數人會更喜歡前者。

對於 gcc 和 g++ 指令,還有其它更多細節方面的區別,這裡不再做更多的贅述。讀完本節,讀者只需要知道,對於 C 語言程式的編譯,我們應該使用 gcc 指令,而編譯 C++ 程式則推薦使用 g++ 指令,這就足夠了。

相關文章