g++ 命令详解与参数实测(Ubuntu 22.04)

g++ 命令逐参数实测:一步编译与 -o、类工程 -c 多文件链接、-std=c++98~c++23 标准矩阵与 __cplusplus 实值、模板与 STL、-Wall/-Wextra/-Wshadow/-Werror 警告矩阵、-O0~-O3 优化与 -g/-s 体积对照、-I/-isystem/-H/-MMD 头文件工具链、-L/-l 链接顺序、-static-libstdc++、-fPIC -shared 动态库、concepts/结构化绑定标准门槛、-D/-dM 宏与彩色诊断,全部回显在 Ubuntu 22.04(g++ 11.4.0)实测通过。

Linux命令g++Linux系统UbuntuUbuntu 22.04命令行2026/10/17

g++ 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 g++ 的每一个常用参数——一步编译与 -o、类工程多文件 -c 链接、-std=c++98~c++23 标准矩阵与 __cplusplus 实值、模板与 STL 编译、警告矩阵 -Wall/-Wextra/-Wpedantic/-Wshadow/-Werror、优化 -O0~-O3/-Os/-Og 与 -g/-s、头文件 -I/-isystem/-H/-MMD、库链接 -L/-l/-static-libstdc++、动态库 -fPIC -shared、-static 全静态、现代特性 concepts/结构化绑定、宏 -D/-dM 与诊断控制,全部命令与回显已在 Ubuntu 22.04(g++ 11.4.0)实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64),root 身份执行
  • g++ 版本:11.4.0(g++ --version 实测:g++ (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0)
  • 与 gcc 11.4.0、GNU Make 4.3、cmake 3.22.1 同属 build-essential 工具链
  • 链接关系实测:/usr/bin/g++ -> g++-11 -> x86_64-linux-gnu-g++-11;/usr/bin/c++ -> /etc/alternatives/c++
  • C++ 头文件搜索链首四项实测:/usr/include/c++/11、/usr/include/x86_64-linux-gnu/c++/11、/usr/include/c++/11/backward、/usr/lib/gcc/x86_64-linux-gnu/11/include
  • 默认语言标准:gnu++17(__cplusplus 实测 201703)

💡 技术拓展:g++ 与 gcc 是同一套 GCC 前端驱动的两个入口,三点差异——g++ 把 .c 之外的后缀按 C++ 编译、自动链接 libstdc++、对 C++ 专属诊断(如模板报错)提供更完整支持。gcc file.cpp 虽也能编译 C++ 语法,但链接阶段缺 libstdc++ 会报 undefined reference。库分发时还常遇到 -static-libstdc++(把 C++ 运行库静态打入,产物可在无对应版本 libstdc++ 的机器上运行)。

二、命令概览

2.1 环境速览

$ g++ --version
g++ (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0
Copyright (C) 2021 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.

$ g++ -dumpversion
11
$ g++ -dumpfullversion
11.4.0
$ g++ -dumpmachine
x86_64-linux-gnu

$ command -v g++
/usr/bin/g++

$ ls -l /usr/bin/g++ /usr/bin/c++
lrwxrwxrwx 1 root root 21 Oct 17 02:00 /usr/bin/c++ -> /etc/alternatives/c++
lrwxrwxrwx 1 root root  6 Aug  5  2021 /usr/bin/g++ -> g++-11

$ ls -l /usr/bin/x86_64-linux-gnu-g++ /usr/bin/g++-11
lrwxrwxrwx 1 root root 23 Dec 18  2025 /usr/bin/g++-11 -> x86_64-linux-gnu-g++-11
lrwxrwxrwx 1 root root  6 Aug  5  2021 /usr/bin/x86_64-linux-gnu-g++ -> g++-11

$ dpkg -l | grep -E "^ii +(g\+\+|gcc-11) "
ii  g++                       4:11.2.0-1ubuntu1        amd64  GNU C++ compiler
ii  gcc-11                    11.4.0-1ubuntu1~22.04.3  amd64  GNU C compiler

$ g++ -print-search-dirs | head -3
install: /usr/lib/gcc/x86_64-linux-gnu/11/
programs: =/usr/lib/gcc/x86_64-linux-gnu/11/:...
libraries: =/usr/lib/gcc/x86_64-linux-gnu/11/:...

$ g++ -v -E -x c++ /dev/null -o /dev/null 2>&1 | sed -n "/search starts here:/,/End of search/p"
#include "..." search starts here:
#include <...> search starts here:
 /usr/include/c++/11
 /usr/include/x86_64-linux-gnu/c++/11
 /usr/include/c++/11/backward
 /usr/lib/gcc/x86_64-linux-gnu/11/include
 /usr/local/include
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.

2.2 --help 与分类帮助

$ g++ --help | head -12
Usage: g++ [options] file...
Options:
  -pass-exit-codes         Exit with highest error code from a phase.
  --help                   Display this information.
  --target-help            Display target specific command line options.
  --help={common|optimizers|params|target|warnings|...}.
                           Display specific types of command line options.
  (Use '-v --help' to display command line options of sub-processes).
  --version                Display compiler version information.
  ...

$ g++ --help | wc -l
61

$ g++ --help=common | head -8
The following options are language-independent:
  --completion=               Provide bash completion for options starting with
                              provided string.
  --debug                     Same as -g.
  ...

$ g++ --target-help 2>&1 | head -5
The following options are target specific:
  -m128bit-long-double        sizeof(long double) is 16.
  -m16                        Generate 16bit i386 code.
  -m32                        Generate 32bit i386 code.

--help=common|optimizers|warnings|target 可分类拉取选项清单,全量选项远多于顶层 --help 的 61 行。

三、基础编译:一步到位与 -o

$ cat hello.cpp
#include <iostream>

int main()
{
    std::cout << "hello, g++!" << std::endl;
    return 0;
}

$ g++ hello.cpp          # 默认输出 a.out
$ ls -l a.out
-rwxr-xr-x 1 root root 16808 Oct 17 02:14 a.out

$ ./a.out
hello, g++!

$ g++ hello.cpp -o hello
$ ./hello
hello, g++!

$ g++ hello.cpp -o /tmp/gxxdemo/basic/hello2    # -o 支持绝对路径
$ ls -l /tmp/gxxdemo/basic/hello2
-rwxr-xr-x 1 root root 16808 Oct 17 02:14 /tmp/gxxdemo/basic/hello2

$ g++ -v hello.cpp -o hello3 2>&1 | tail -4
 /usr/lib/gcc/x86_64-linux-gnu/11/collect2 ... -o hello3 ...
COLLECT_GCC_OPTIONS='-v' '-o' 'hello3' '-mtune=generic' '-march=x86-64' '-dumpdir' 'hello3.'

同一源码,g++ 产物(16808 字节)比 gcc 的 C 版(15960)略大——libstdc++ 的 iostream 启动骨架。

四、-c 与多文件类工程

$ cat counter.h
#ifndef COUNTER_H
#define COUNTER_H

#include <string>

class Counter
{
public:
    explicit Counter(std::string name);
    void incr();
    int value() const;
    const std::string &name() const;

private:
    std::string name_;
    int count_ = 0;
};

#endif

$ g++ -c counter.cpp        # 只编译不链接 → counter.o
$ g++ -c main.cpp           # → main.o
$ g++ -c main.cpp -o main_obj.o
$ ls -l *.o
-rw-r--r-- 1 root root  2832 Oct 17 02:14 counter.o
-rw-r--r-- 1 root root  2456 Oct 17 02:14 main.o
-rw-r--r-- 1 root root  2456 Oct 17 02:14 main_obj.o

$ g++ main.o counter.o -o app
$ ./app
demo = 3

$ g++ main.cpp counter.cpp -o app_all    # 一步到位
$ ./app_all
demo = 3

$ g++ -c counter.cpp main.cpp           # -c 一次接多个源文件

$ g++ main.o -o app_bad                  # 少链接 counter.o
/usr/bin/ld: main.o: in function `main':
main.cpp:(.text+0x2e): undefined reference to `Counter::incr()'
/usr/bin/ld: main.cpp:(.text+0x45): undefined reference to `Counter::value()'
collect2: error: ld returned 1 exit status

C++ 的 undefined reference 报错会以修饰名(mangled name,如 Counter::incr())显示,可直接定位类与成员函数。

五、-std 标准矩阵与 __cplusplus

$ cat std.cpp
#include <cstdio>

int main()
{
    printf("__cplusplus = %ld\n", __cplusplus);
    return 0;
}

$ g++ -std=c++98 std.cpp -o s98 && ./s98
__cplusplus = 199711

$ g++ -std=c++11 std.cpp -o s11 && ./s11
__cplusplus = 201103

$ g++ -std=c++14 std.cpp -o s14 && ./s14
__cplusplus = 201402

$ g++ -std=c++17 std.cpp -o s17 && ./s17
__cplusplus = 201703

$ g++ -std=c++20 std.cpp -o s20 && ./s20
__cplusplus = 202002

$ g++ -std=c++23 std.cpp -o s23 && ./s23
__cplusplus = 202100

$ g++ std.cpp -o sdefault && ./sdefault     # 不加 -std
__cplusplus = 201703                        # 默认 gnu++17

$ g++ -std=gnu++17 std.cpp -o g17 && ./g17
__cplusplus = 201703

$ g++ -std=c++2a std.cpp -o s2a && ./s2a    # c++2a 是 c++20 的旧拼写,仍兼容
__cplusplus = 202002

新特性代码在不同标准下的行为对照:

$ cat feature.cpp
#include <cstdio>

int main()
{
    auto x = 42;  /* C++11 起 */
    printf("%d\n", x);
    return 0;
}

$ g++ -std=c++98 feature.cpp -o f98
feature.cpp:5:10: error: 'x' does not name a type
    5 |     auto x = 42;
      |          ^

$ g++ -std=c++11 feature.cpp -o f11 && ./f11
42
-std 取值含义__cplusplus 实测
c++98ISO C++98199711
c++11ISO C++11201103
c++14ISO C++14201402
c++17 / c++2aISO C++17 / 20 旧拼法201703 / 202002
c++20ISO C++20202002
c++23ISO C++23(实验性)202100
(默认)/ gnu++17GNU 扩展版 C++17201703

六、模板与 STL 工程

$ cat maxval.hpp
#ifndef MAXVAL_HPP
#define MAXVAL_HPP

template <typename T>
const T &maxval(const T &a, const T &b)
{
    return a < b ? b : a;
}

#endif

$ cat main.cpp
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "maxval.hpp"

int main()
{
    std::vector<int> v{3, 1, 4, 1, 5, 9, 2, 6};
    std::map<std::string, int> ages{{"alice", 30}, {"bob", 25}};
    std::cout << "max=" << maxval(3, 9) << '\n';
    for (const auto &[name, age] : ages)
        std::cout << name << ":" << age << ' ';
    std::cout << '\n';
    return 0;
}

$ g++ -std=c++17 main.cpp -o app
$ ./app
max=9
alice:30 bob:25

$ g++ -std=c++17 -O2 main.cpp -o app_o2 && ./app_o2
max=9
alice:30 bob:25

$ g++ -std=c++98 main.cpp -o app98
main.cpp:9:22: error: in C++98 'v' must be initialized by constructor, not by '{...}'
main.cpp:12:21: error: expected '[' before '&' token     # 结构化绑定是 C++17 特性
    12 |     for (const auto &[name, age] : ages)

$ g++ -std=c++11 main.cpp -o app11
main.cpp:12:22: warning: structured bindings only available with '-std=c++17' or '-std=gnu++17'

模板函数必须放头文件(实例化点需要完整定义);列表初始化与结构化绑定分别受 C++11/C++17 门槛限制,错误信息会给出"only available with ..."提示。

七、警告矩阵:-Wall / -Wextra / -Wpedantic / -Wshadow / -Werror

int unused_var = 7;          // 未使用
int x = 1;
{
    double x = 3.14;         // 遮蔽外层 x
}
if (x = 2)                   // 条件里赋值
char c = 300;                // 溢出窄化

实测各开关命中的警告:

$ g++ warn.cpp -o w1
warn.cpp:13:14: warning: overflow in conversion from 'int' to 'char' ... [-Woverflow]

$ g++ -Wall warn.cpp -o w2
warn.cpp:11:11: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
warn.cpp:13:14: warning: overflow in conversion from 'int' to 'char' ... [-Woverflow]
warn.cpp:5:9:   warning: unused variable 'unused_var' [-Wunused-variable]

$ g++ -Wall -Wextra warn.cpp -o w3      # 与 -Wall 相同(本例无参数类问题)

$ g++ -Wall -Wextra -Wpedantic warn.cpp -o w4   # 严格 ISO 检查,多出扩展语法告警

$ g++ -Wall -Wextra -Wshadow warn.cpp -o w5
warn.cpp:7:16: warning: declaration of 'x' shadows a previous local [-Wshadow]
    7 |         double x = 3.14;

$ g++ -Wall -Wextra -Werror warn.cpp -o w6
warn.cpp:11:11: error: suggest parentheses around assignment used as truth value [-Werror=parentheses]
...

$ g++ -w warn.cpp -o w7                 # -w 全静默

要点:变量遮蔽(shadow)必须显式加 -Wshadow,其余常用项 -Wall 基本覆盖;CI 建议统一 -Wall -Wextra -Wshadow -Werror。

八、优化等级与体积控制

STL 密集代码(vector + string)在六档优化下的实测:

$ g++ -O0 heavy.cpp -o h_O0
$ g++ -O1 heavy.cpp -o h_O1
$ g++ -O2 heavy.cpp -o h_O2
$ g++ -O3 heavy.cpp -o h_O3
$ g++ -Os heavy.cpp -o h_Os
$ g++ -Og -g heavy.cpp -o h_Og
$ ls -l h_O0 h_O1 h_O2 h_O3 h_Os h_Og
-rwxr-xr-x 1 root root  27128 Oct 17 02:50 h_O0
-rwxr-xr-x 1 root root  16816 Oct 17 02:50 h_O1
-rwxr-xr-x 1 root root  16896 Oct 17 02:50 h_O2
-rwxr-xr-x 1 root root  16784 Oct 17 02:50 h_O3
-rwxr-xr-x 1 root root 109648 Oct 17 02:50 h_Og    # -Og -g 带全量调试信息
-rwxr-xr-x 1 root root  17128 Oct 17 02:50 h_Os

$ ./h_O0 && ./h_O3      # 两次输出一致,优化不改变语义
332833500 333283335000

$ g++ -O2 -g heavy.cpp -o h_g && ls -l h_O2 h_g
-rwxr-xr-x 1 root root  16896 Oct 17 02:50 h_O2
-rwxr-xr-x 1 root root 110000 Oct 17 02:50 h_g     # -g 附带 DWARF

$ g++ -O2 -s heavy.cpp -o h_s && ls -l h_O2 h_s
-rwxr-xr-x 1 root root 16896 Oct 17 02:50 h_O2
-rwxr-xr-x 1 root root 14568 Oct 17 02:50 h_s      # -s 剥离符号表

$ g++ -O2 -march=native heavy.cpp -o h_native && ./h_native
332833500 333283335000

C++ 代码 -O0 与 -O1 体积差 10KB(iostream 内联展开策略不同);-O3 未必比 -O2 大(模板实例去重);调试信息让体积翻 6 倍。

九、头文件搜索:-I / -isystem / -H / -MM

$ mkdir -p incs && cat > incs/myutil.hpp
#pragma once
namespace myutil
{
    inline int twice(int x) { return 2 * x; }
}

$ g++ main.cpp -o a1
main.cpp:2:10: fatal error: myutil.hpp: No such file or directory
    2 | #include <myutil.hpp>

$ g++ -Iincs main.cpp -o a2 && ./a2      # -I 紧贴路径(最常用写法)
42

$ g++ -I incs main.cpp -o a3 && ./a3     # -I 与路径分离亦可
42

$ g++ -isystem incs main.cpp -o a4 && ./a4   # 标记为系统目录,抑制其中警告
42

$ g++ -Iincs -H main.cpp -o a5 2>&1 | head -6    # -H 逐层展示头文件包含树
. /usr/include/c++/11/iostream
.. /usr/include/x86_64-linux-gnu/c++/11/bits/c++config.h
... /usr/include/x86_64-linux-gnu/c++/11/bits/os_defines.h
.... /usr/include/features.h
..... /usr/include/features-time64.h
...... /usr/include/x86_64-linux-gnu/bits/wordsize.h

$ g++ -Iincs -MM main.cpp                # 生成 Make 依赖规则
main.o: main.cpp incs/myutil.hpp

$ g++ -Iincs -MMD main.cpp -o a6 && cat a6.d
a6: main.cpp incs/myutil.hpp

⚠️ -MMD 的产物名跟随 -o 输出名(这里是 a6.d),不叫 main.d——写 Makefile 的 %.d: %.cpp 规则时要用 $(*:.o=.d) 类的推导,别硬编码源文件名。

十、库链接:-L / -l / -static-libstdc++

$ g++ -c mymath.cpp && ar rcs libmylib.a mymath.o

$ g++ main.cpp -lmylib -o bad_noflag        # 不加 -L 找不到当前目录的库
/usr/bin/ld: cannot find -lmylib

$ g++ main.cpp -L. -lmylib -o app
$ ./app
area=12.5664

$ g++ -L. -lmylib main.cpp -o bad_order     # 库写在源文件之前
/usr/bin/ld: main.cpp:(.text+0x2e): undefined reference to `mymath::circle_area(double)'

$ g++ main.cpp -L. -lmylib -static-libstdc++ -static-libgcc -o app_static
$ ./app_static
area=12.5664

$ ldd app | grep -E "stdc|gcc"
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007b584e173000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007b584de43000)

$ ldd app_static | grep -cE "stdc|gcc_s"
0

-static-libstdc++ -static-libgcc 把 C++/GCC 运行库静态打入(libstdc++.so.6 从依赖表消失),产物可分发到没有对应运行库版本的目标机;业务代码仍默认动态。注意 libstdc++ 默认是动态链接的,且链接顺序规则与 gcc 相同(被依赖库放后)。

十一、动态库:-fPIC -shared 与运行期路径

$ g++ -fPIC -c mymath.cpp -o mymath_pic.o
$ g++ -shared mymath_pic.o -o libmymath.so
$ ls -l libmymath.so
-rwxr-xr-x 1 root root 15232 Oct 17 02:50 libmymath.so

$ g++ main.cpp -L. -lmymath -o app_so
$ ldd app_so | grep mymath
        libmymath.so => not found

$ ./app_so
./app_so: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory

$ LD_LIBRARY_PATH=. ./app_so
area=12.5664

$ g++ main.cpp ./libmymath.so -o app_so2    # 直接把 .so 路径当输入,链接期记录绝对/相对路径
$ ldd app_so2 | grep mymath
        ./libmymath.so (0x00007fc2b6cf3000)

$ LD_LIBRARY_PATH=. ./app_so2
area=12.5664

$ g++ -fPIC -shared mymath.cpp -o libmymath2.so   # 一步法:-fPIC -shared 直接接源文件
$ ls -l libmymath2.so
-rwxr-xr-x 1 root root 15232 Oct 17 02:50 libmymath2.so

十二、-static 全静态

$ g++ main.cpp -L. -lmymath -o app_a           # 默认动态
$ g++ main.cpp -L. -lmymath -static-libstdc++ -static-libgcc -o app_sl
$ g++ main.cpp -L. -lmymath -static -o app_st  # 全静态

$ ls -l app_a app_sl app_st
-rwxr-xr-x 1 root root   16600 Oct 17 02:50 app_a
-rwxr-xr-x 1 root root 1370784 Oct 17 02:50 app_sl
-rwxr-xr-x 1 root root 2404064 Oct 17 02:50 app_st

$ ldd app_a | grep -E "stdc|gcc_s"
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007b584e173000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007b584de43000)

$ ldd app_sl | grep -cE "stdc|gcc_s"
0

$ ldd app_st
        not a dynamic executable

$ ./app_st
area=12.5664

三档体积:动态 16KB → 运行库静态 1.3MB → 全静态 2.4MB。

十三、现代 C++ 特性与标准门槛

$ cat mod17.cpp
#include <iostream>
#include <map>
#include <string>

int main()
{
    auto add = [](auto a, auto b) { return a + b; };        // 泛型 lambda(C++14)
    std::map<std::string, int> m{{"k", 1}, {"j", 2}};
    for (const auto &[key, val] : m)                         // 结构化绑定(C++17)
        std::cout << key << '=' << val << ' ';
    std::cout << "| add(1,2.5)=" << add(1, 2.5) << '\n';
    constexpr int n = 5;
    static_assert(n == 5, "n must be 5");
    return 0;
}

$ g++ -std=c++17 mod17.cpp -o m17 && ./m17
j=2 k=1 | add(1,2.5)=3.5

$ g++ -std=c++11 mod17.cpp -o m11
mod17.cpp:9:22: warning: structured bindings only available with '-std=c++17' or '-std=gnu++17'

$ cat mod20.cpp
#include <iostream>
#include <type_traits>
#include <vector>

template <typename T>
concept Numeric = std::is_arithmetic_v<T>;       // concepts(C++20)

template <Numeric T>
T twice(T x) { return x * 2; }

int main()
{
    std::cout << twice(21) << ' ' << twice(2.5) << '\n';
    std::vector v{1, 2, 3};                       // CTAD 类模板实参推导
    for (auto x : v)
        std::cout << x << ' ';
    std::cout << '\n';
    return 0;
}

$ g++ -std=c++20 mod20.cpp -o m20 && ./m20
42 5
1 2 3

$ g++ -std=c++17 mod20.cpp -o m20b
mod20.cpp:5:1: error: 'concept' only available with '-std=c++20' or '-std=gnu++20'
    5 | concept Numeric = std::is_arithmetic_v<T>;

map 输出 j=2 k=1(按 key 字典序)再次印证关联式序列的标准行为;concepts 需要 -std=c++20,错误提示会直接给出可用标准。

十四、宏定义:-D / -U / -dM

$ cat macro.cpp
#include <iostream>

int main()
{
#ifdef VERSION_NAME
    std::cout << "build: " << VERSION_NAME << '\n';
#else
    std::cout << "build: unknown\n";
#endif
#ifdef DEBUG_LEVEL
    std::cout << "debug=" << DEBUG_LEVEL << '\n';
#endif
    std::cout << "cplusplus=" << __cplusplus << " gnu=" << __GNUC__ << '\n';
    return 0;
}

$ g++ macro.cpp -o m1 && ./m1
build: unknown
cplusplus=201703 gnu=11

$ g++ -DVERSION_NAME='"v1.0.0"' macro.cpp -o m2 && ./m2
build: v1.0.0

$ g++ -DDEBUG_LEVEL=2 macro.cpp -o m3 && ./m3
build: unknown
debug=2

$ g++ -DDEBUG_LEVEL=2 -UDEBUG_LEVEL macro.cpp -o m4 && ./m4   # -U 反向取消
build: unknown
cplusplus=201703 gnu=11

$ echo | g++ -dM -E -x c++ - | grep -E " __cplusplus| __GNUC__ | __linux | __x86_64"
#define __cplusplus 201703L
#define __GNUC__ 11
#define __linux 1
#define __x86_64 1

十五、编译阶段拆分与产物命名

$ g++ -E stage.cpp -o stage.i && ls -l stage.i
-rw-r--r-- 1 root root 778397 Oct 17 02:50 stage.i      # iostream 展开后 77 万字符

$ grep -c "" stage.i
32261

$ grep GREET stage.i                                      # 宏已替换,无残留

$ g++ -S stage.cpp -o stage.s && head -8 stage.s
        .file   "stage.cpp"
        .text
        .local  _ZStL8__ioinit                            # 修饰名
        .comm   _ZStL8__ioinit,1,1
        .section        .rodata
.LC0:
        .string "hi"

$ g++ -c stage.cpp -o stage.o
$ g++ stage.o -o stage_bin && ./stage_bin
hi, g++

$ g++ -save-temps stage.cpp -o st && ls st*               # gcc 11 产物命名
st  st-stage.ii  st-stage.o  st-stage.s

$ head -3 st-stage.ii
# 1 "stage.cpp"
# 1 "<built-in>"
# 1 "<command-line>"

⚠️ gcc 11 的 -save-temps 产物为 <output>-<source基名> 格式(st-stage.ii/.o/.s),不是老文档写的 st.ii;C++ 预处理产物后缀是 .ii。

十六、错误诊断与颜色控制

$ cat syntax.cpp
#include <iostream>

int main()
{
    std::cout << "missing semicolon"
    return 0;
}

$ g++ syntax.cpp -o s1
syntax.cpp: In function 'int main()':
syntax.cpp:5:32: error: expected ';' before 'return'
    5 |     std::cout << "missing semicolon"
      |                                ^
      |                                ;

$ g++ -fmax-errors=3 syntax.cpp -o s2      # 限制最多报 3 条错误

$ g++ -fdiagnostics-color=always syntax.cpp -o s3 2>&1 | head -6 | cat -v
syntax.cpp: In function 'int main()':
syntax.cpp:5:32: error: expected ^[[01m^[[K';'^[[m^[[K before ^[[01m^[[K'return'^[[m^[[K
    5 |     std::cout << "missing semicolon"       # ^[[01m 等为 ANSI 颜色码
      |                                ^[[01m^[[K^[[m^[[K^[[01m^[[K;
...

$ cat ref.cpp
extern void not_defined(int);

int main()
{
    not_defined(1);
    return 0;
}

$ g++ ref.cpp -o r1
/usr/bin/ld: /tmp/ccG9oQ3t.o: in function `main':
ref.cpp:(.text+0x16): undefined reference to `not_defined(int)'
collect2: error: ld returned 1 exit status

$ g++ -w syntax.cpp -o w1                  # -w 静默后错误仍会报(只压警告,不压错误)
报错关键行阶段处置
error: expected ';' / does not name a type编译期源码语法
'concept' only available with '-std=c++20'编译期升 -std
fatal error: xxx.hpp: No such file or directory预处理期-I 或装 dev 包
undefined reference to 'Class::method()'链接期补 .o/库、修链接顺序
cannot find -lxxx链接期补 -L
error while loading shared libraries运行期LD_LIBRARY_PATH/rpath
structured bindings only available with -std=c++17警告升标准

十七、参数速查表

参数作用实测要点
-o <file>输出名默认 a.out
-c只编译不链接产出 .o;缺链接报 mangled 名
-E / -S预处理 / 汇编.i(C++ 为 .ii)/ .s
-save-temps保留中间产物gcc 11 命名为 out-src.ii/.o/.s
-std=c++98~c++23语言标准默认 gnu++17;c++2a=c++20
-Wall -Wextra警告包-Wshadow 需显式加
-Wpedantic严格 ISO 告警报扩展语法
-Werror / -w警告升级 / 静默不影响真正的 error
-O0~-O3 / -Os / -Og优化档STL 码 O0 27KB → O1 17KB
-g / -s加调试信息 / 剥符号110KB / 14.5KB 对照
-march=native按本机 CPU 生成产物不可跨机型
-I<dir> / -isystem头文件目录 / 系统级-isystem 抑制其中警告
-H打印包含树层级前缀 . ..
-MM / -MMD生成 Make 依赖.d 名跟随 -o 输出名
-L<dir> / -l<name>库路径 / 库名被依赖库放后
-static-libstdc++ -static-libgcc运行库静态ldd 不再显示 libstdc++
-fPIC -shared动态库可一步 g++ -fPIC -shared src
-static全静态16KB→2.4MB 对照
-D<name>=<val> / -U<name>定义 / 取消宏字符串值 '"v1.0.0"'
-dM -E -x c++导出预定义宏含 __cplusplus
-fmax-errors=N限制报错条数大模板排错友好
-fdiagnostics-color=always强制彩色诊断日志系统需配套终端解释
--help=common分类选项清单common/optimizers/warnings/target

关联阅读:gcc(C 编译驱动,管线与库链接同源)、make(增量构建编排)、cmake(构建系统生成器,CXX_STANDARD/CMAKE_BUILD_TYPE 的底层就是本文的 -std 与 -O)见本专栏姊妹篇。