macOS 中神祕的 GCC
gcc
是 GCC 中的 GUN C Compiler,C 編譯器。
g++
是 GCC 中的 GUN C++ Compiler,C++編譯器。
就本質而言, gcc
和 g++
並不是編譯器,也不是編譯器的集合,它們只是一種驅動器,根據引數中要編譯的檔案的型別,呼叫對應的 GUN 編譯器而已。
gcc
與 g++
都可以編譯 C 和 C++ 檔案,只是處理方式不同。 可以參考 ofollow,noindex">GCC的gcc和g++區別 這篇文章。
交換變數-指標
下面這段程式碼很簡單,利用 C 指標實現交換兩個變數的目的。
原始檔:mz_swap.c
#include <stdio.h> // 使用指標的方式交換兩個變數 int mz_swap(int *ap, int *bp); int main(int argc, char * argv[]) { int xp = 901; int yp = 902; printf("--Before-- xp = %i, yp = %i\n", xp, yp); mz_swap(&xp, &yp); printf("--After--- xp = %i, yp = %i\n", xp, yp); return 0; } int mz_swap(int *ap, int *bp) { if (NULL == ap || NULL == bp) { return -1; } int tp = *ap; *ap = *bp; *bp = tp; return 0; }
在 macOS 下使用 gcc
編譯 mz_swap.c
,產生可執行檔案 exec_main.out
,如下操作:
gcc mz_swap.c -o exec_main.out
編譯成功,執行 ./exec_main.out
,正常輸出結果:
--Before-- xp = 901, yp = 902 --After--- xp = 902, yp = 901
採用 g++ 來編譯,如下操作:
g++ mz_swap.c -o exec_main.out
報出如下警告,該警告的意思是在 C++ 模式下強制編譯 C 檔案,這裡可以不予理會。
clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]
雖然有警告,但是編譯可以產生可執行檔案 exec_main.out
且可以正常執行的,執行結果跟上面一樣。
交換變數-引用
大家都知道,C 沒有 引用
這個概念,而 C++ 是有 引用
概念的,可以在此瞭解 C++ 引用 .
試一下使用 gcc
編譯使用 引用
方式編寫的 C 程式碼,按照說法, gcc
是無法編譯通過的。
原始檔:mz_swap_ref.c
#include <stdio.h> // 使用引用的方式交換兩個變數 int mz_swap_ref(int ≈, int &bp); int main(int argc, char * argv[]) { int xp = 901; int yp = 902; printf("--Before-- xp = %i, yp = %i\n", xp, yp); mz_swap_ref(xp, yp); printf("--After--- xp = %i, yp = %i\n", xp, yp); return 0; } int mz_swap_ref(int ≈, int &bp) { int tp = ap; ap = bp; bp = tp; return 0; }
編譯
gcc mz_swap_ref.c -o exec_main.out
編譯失敗,錯誤資訊如下:
mz_swap_ref.c:4:21: error: expected ')' int mz_swap_ref(int ≈, int &bp); ^ mz_swap_ref.c:4:16: note: to match this '(' int mz_swap_ref(int ≈, int &bp);
既然按照 C 的編譯方式不行,那就換成 g++
來編譯。
g++ mz_swap_ref.c -o exec_main.out
編譯成功,執行可執行檔案
./exec_main.out
--Before-- xp = 901, yp = 902 --After--- xp = 902, yp = 901
大家可以自己動手試試,使用 clang 來編譯 mz_swap_ref.c
和使用 gcc
來編譯都是報錯,使用 clang++
和 g++
編譯都是沒有問題的。
在部落格 Homebrew-%E5%AE%89%E8%A3%85-GCC-%E5%92%8C-Binutils/" target="_blank" rel="nofollow,noindex">GCC: Homebrew 安裝 GCC 和 Binutils 中,我已經分享了在 macOS 中的 gcc
和 g++
不是 GNU 提供的,而是 Apple 自己的 clang。
這裡要說明的是即使使用自己安裝的 gcc( gcc-4.9
) 來編譯 mz_swap_ref.c
也是無法編譯通過的,驗證如下:
gcc-4.9 mz_swap_ref.c -o exec_main.out
錯誤資訊:
mz_swap_ref.c:4:21: error: expected ';', ',' or ')' before '&' token int mz_swap_ref(int ≈, int &bp); ^ mz_swap_ref.c:20:21: error: expected ';', ',' or ')' before '&' token int mz_swap_ref(int ≈, int &bp) {^
gcc、g++ 和 clang 的關係
在 macOS 中, gcc
以某種方式指向 llvm-gcc
編譯器, g++
亦如此。
In Apple's version of GCC, both cc and gcc are actually symbolic links to the llvm-gcc compiler. Similarly, c++ and g++ are links to llvm-g++.
llvm-gcc
是 c/c++/oc 的編譯器,用了 gcc
前端和命令列介面的 llvm.
llvm-gcc is a C, C++, Objective-C and Objective-C++ compiler. llvm-g++ is a compiler driver for C++. llvm-gcc uses gcc front-end and gcc's command line interface.
接下來,我們看一下 llvm-gcc
,可以使用 which llvm-gcc
看一下 llvm-gcc
所在位置是 /usr/bin/llvm-gcc
,開啟目錄可以看出其實是一個符號連結,如下圖所示:

ls -l /usr/bin/llvm-gcc
/usr/bin/llvm-gcc -> clang
它們是統一指向 clang
的符號連結,可以看其原始指向, llvm-gcc
指向 clang
, llvm-g++
指向 clang++
。
二者都在 /usr/bin/
目錄下:

其實在 macOS 中 cc
編譯器也指向 clang
。
總結
通過上面的例子,我們至少可以學到如下幾點知識:
1. C 語言規範中沒有 引用
的概念,使用 C 編譯器無法使其編譯通過,但是使用 C++ 編譯器是可以編譯通過的。這是因為各自的編譯器是遵循語言規範的。
2. macOS 中的 gcc
和 g++
蘋果開發者們並沒有去改造和重寫它們,只是分別指向 clang
和 clang++
編譯器。
3. 如果不想使用 macOS 中的 gcc
和 g++
,就需要自己重新安裝 GNU 的,安裝和使用方法已經在部落格中有說明。
掃碼關注,你我就各多一個朋友~