2. GCC/G++编译器入门

说实话,很多C++初学者一上来就被各种IDE惯坏了。点一下运行按钮,代码就跑了。但你真的知道背后发生了什么吗?我个人觉得,搞C++如果不了解GCC/G++,就像开车不懂发动机——能开,但永远成不了老司机。

这一章,咱们就聊聊GCC/G++。我会从安装讲起,再到基本命令,最后把那些常用的编译选项掰开揉碎了说清楚。嗯,都是我在项目里踩过坑、流过泪换来的经验。

2.1 GCC/G++是什么?

GCC,全称GNU Compiler Collection。它是个编译器家族,支持C、C++、Java、Fortran等多种语言。G++是GCC里专门编译C++的那个工具。

说白了,GCC处理.c文件,G++处理.cpp文件。但实际工作中,我习惯直接用g++编译C++代码,省心。

核心区别:

  • gcc:根据文件后缀名决定编译语言,链接时默认不链接C++标准库
  • g++:默认将文件当作C++编译,自动链接C++标准库

2.2 安装GCC/G++

不同平台安装方式不一样。我当年在Windows上折腾了好久,后来发现用Linux才是最舒服的。

Linux(Ubuntu/Debian)

sudo apt update
sudo apt install build-essential
g++ --version

build-essential是个元包,会把gcc、g++、make等工具一起装好。我个人建议新手直接装这个,省得后面缺这缺那。

macOS

xcode-select --install

或者用Homebrew:

brew install gcc

Windows

Windows下我推荐用MinGW-w64。下载安装后,记得把bin目录加到系统PATH里。我曾经在这步吃过亏——装完了以为万事大吉,结果命令行里敲g++死活找不到。

注意:Windows用户安装完成后,务必打开命令行输入 g++ --version 验证。如果提示"不是内部或外部命令",那就是PATH没配好。

2.3 基本编译命令

先写个最简单的程序:

// hello.cpp
#include <iostream>
int main() {
    std::cout << "Hello, GCC!" << std::endl;
    return 0;
}

编译它:

g++ hello.cpp -o hello
./hello

就这么简单?对,就这么简单。但实际项目里,没人会这么干。你想想看,一个项目几十个源文件,难道每次都敲一遍?

我刚开始工作时,就是一行行敲命令。后来项目大了,发现根本记不住哪些文件需要编译。嗯,那时候我才意识到Makefile的重要性——不过那是后面章节的事了。

2.4 常用编译选项详解

这才是重点。GCC/G++的编译选项多如牛毛,但常用的也就那么十几个。我按使用频率给你排个序:

2.4.1 输出文件控制

选项 作用 示例
-o 指定输出文件名 g++ main.cpp -o app
-E 只进行预处理 g++ -E main.cpp -o main.i
-S 只编译到汇编 g++ -S main.cpp -o main.s
-c 只编译不链接 g++ -c main.cpp -o main.o

这里有个坑:-o选项必须紧跟在源文件后面,或者放在最后。我曾经写过g++ -o hello hello.cpp,没问题。但有人写成g++ hello.cpp hello -o,编译直接报错。

2.4.2 警告选项

我最看重这个。写C++不开警告,等于裸奔。

选项 作用
-Wall 开启大多数常见警告
-Wextra 开启额外警告
-Werror 把警告当作错误处理
-pedantic 严格遵循C++标准

我的习惯:开发阶段用 -Wall -Wextra,发布前加上 -Werror。这样能逼自己把代码写干净。我曾经在一个项目里因为没开-Wall,漏掉了一个未初始化变量的警告,结果线上出了个诡异的bug,查了整整两天。

2.4.3 优化选项

优化等级决定了编译器怎么帮你提速。

选项 说明
-O0 不做优化,调试用
-O1 基础优化
-O2 推荐优化等级,兼顾速度与体积
-O3 激进优化,可能增加代码体积
-Os 优化体积

为什么会这样?-O2和-O3的区别在于,-O3会启用一些循环展开、函数内联等激进优化。但有时候-O3反而会引入bug——我遇到过,一个函数在-O2下跑得好好的,换成-O3就崩了。所以发布前一定要测试。

2.4.4 调试与标准选项

选项 作用
-g 生成调试信息,配合GDB使用
-std=c++11/14/17/20 指定C++标准版本

我建议新项目一律用-std=c++17或-std=c++20。老项目嘛,看情况。有些公司还在用C++11,你强行上C++20,编译不过就尴尬了。

2.5 完整编译流程

GCC/G++的编译分四步:预处理 → 编译 → 汇编 → 链接。我画了个图,帮你理解:

预处理 -E 选项 编译 -S 选项 汇编 -c 选项 链接 无选项 .cpp → .i .i → .s .s → .o .o → 可执行文件 完整编译命令示例 g++ -Wall -O2 -std=c++17 -g main.cpp -o main ↑ 一步完成四步,实际工作中最常用

你想想看,平时我们敲g++ main.cpp -o main,其实背后就是这四步一气呵成。但如果你只想检查预处理结果,或者只想生成目标文件,就可以用对应的选项停下来。

2.6 实战:一个完整的编译命令

把上面学的串起来,写个正经的编译命令:

g++ -Wall -Wextra -Werror -O2 -std=c++17 -g main.cpp utils.cpp -o myapp

这条命令干了什么?

  • -Wall -Wextra -Werror:开启所有警告,并当作错误处理
  • -O2:二级优化
  • -std=c++17:使用C++17标准
  • -g:生成调试信息
  • main.cpp utils.cpp:两个源文件
  • -o myapp:输出名为myapp

避坑指南:我曾经在一个项目里,把-std=c++17写成了-std=c++17(少了个等号),结果编译器报了一堆看不懂的错误。后来才发现是语法问题。嗯,这种低级错误,犯过一次就记住了。

2.7 小结

这一章我们聊了GCC/G++的安装、基本命令和常用选项。说白了,核心就三点:

  • 安装:Linux用build-essential,Windows用MinGW
  • 基本命令:g++ 源文件 -o 输出文件
  • 常用选项:-Wall -O2 -std=c++17 -g 这四件套,基本够用

记住,编译选项不是越多越好。够用就行。我见过有人把几十个选项堆在一起,结果编译速度慢得离谱,还容易出问题。