g++编译C++文件时必须用g++而非gcc,因gcc不自动链接libstdc++导致undefined reference错误;应显式指定-std=c++17、-Wall -Wextra -Werror -g,并确保-l库选项置于源文件之后。

用 g++ 编译 C++ 文件,别用 gcc
直接用 gcc 编译 .cpp 文件会链接失败,常见报错是 undefined reference to `std::cout' 或 _ZSt4cout 一类符号未定义。这是因为 gcc 默认不链接 C++ 标准库(libstdc++),而 g++ 会自动加上 -lstdc++ 和其他必要参数。
正确做法始终是:
- 源文件后缀为
.cpp、.cc、.cxx时,统一用g++命令 -
g++ main.cpp -o main是最简可行命令,等价于gcc -xc++ -lstdc++ -shared-libgcc main.cpp -o main - 即使只写
#include <iostream></iostream>且没用到 STL,也建议用g++,避免隐式依赖漏掉
-std= 必须显式指定 C++ 标准版本
不加 -std= 时,g++ 默认行为因版本而异:g++ 11 默认 c++14,g++ 13 默认 c++17,g++ 14 默认 c++20。跨机器编译时极易出错——比如某台机器能编译通过的 std::optional,换一台老版本 g++ 就报错。
稳妥写法:
立即学习“C++免费学习笔记(深入)”;
- 新手起步统一用
-std=c++17:特性足够新(如structured bindings、if constexpr),兼容性又比c++20好 - 项目明确要求 C++20 特性(如
concepts、ranges)才用-std=c++20,并确认 CI 环境支持 - 绝对不要依赖默认值;CI 配置、Makefile、IDE 构建设置里都得显式写死
-Wall -Wextra -Werror 不是可选项,是启动门槛
新手常跳过警告,结果 int x = 0; if (x = 1) { ... } 这种赋值当判断的 bug 直接进生产。而 -Wall -Wextra 能捕获这类问题,-Werror 把警告转成错误,强制你当场修复。
推荐最小安全组合:
g++ -std=c++17 -Wall -Wextra -Werror -g main.cpp -o main-
-g生成调试信息,后续用gdb查问题不抓瞎 - 如果用了第三方头文件(如 Boost),可临时加
-Wno-unused-parameter避免干扰,但不要关-Werror - CI 流水线必须带
-Werror,本地开发也建议打开——早修比晚查成本低得多
链接外部库时,-l 和 -L 的顺序不能乱
报错 undefined reference to `foo()' 不一定是函数没实现,很可能是链接器找不到库。关键点在于:-l 参数必须放在目标文件(.o 或源文件)之后,否则会被忽略。
例如要链接 libz:
- ✅ 正确:
g++ -std=c++17 main.cpp -lz -o main - ❌ 错误:
g++ -std=c++17 -lz main.cpp -o main(-lz在源文件前,链接器可能跳过) - 若库不在标准路径(如
/usr/lib),用-L/path/to/lib指定目录,同样要放源文件之后:g++ main.cpp -L/opt/mylib -lmylib -o main - 用
g++ -v main.cpp可看到完整链接命令,验证-l是否出现在collect2调用末尾
真正容易被忽略的是:C++ 模板、内联函数、constexpr 的符号不进目标文件,它们只在编译期展开。所以哪怕 .o 文件里没报错,链接时也可能因模板实例化缺失而失败——这时得检查头文件包含是否完整、是否遗漏了显式实例化声明。


















