C/C++ 建议编译选项
警告选项
在程序设计中,我们可能不小心写出一些不合常理的代码语句。大部分情况下,这会使程序行为脱离我们的本意。使编译器发出警告可以在一定程度下规避这种情况。
-Wall
启动常见的警告选项,包括但不限于:
- 未使用的变量、函数或标签
- 未初始化的自动变量
- 格式化字符串不匹配
- 悬空的控制表达式(
if-else
嵌套有歧义) - 可能的除零操作
- 空的循环体
- 浮点数比较
-Wextra
额外包括一些警告选项,包括但/不限于:
- 空指针解引用
- 废弃的函数调用
- 隐式堕落(
switch
忘记break
) - 可能的未定义行为
没有列举本人认为 OI 中不常用的选项,如“枚举值与整数值的比较”。
-Wformat=2
比上述 -Wall
中包含项更高级别的格式化字符串检查。
-Wpedantic
警告不符合严格标准的代码(编译器可能提供了扩展语法)
例子
例如,编译器可能提供栈空间上的变长数组声明:
{ int n; cin >> n; int arr[n]; ... }
这在标准中是不被允许的,但可能作为扩展语法。
-Wshadow
警告变量覆盖。
尽管这可能是 C++ 的实用语法之一,但是使用同名变量可能引发不必要的麻烦。
题外话
前几天知道了一个命名空间的古怪语法:
int foo; int main() { int foo; cin >> foo >> ::foo; }
在上述代码中,
foo
指代main
函数内声明的变量,::foo
指代全局作用域内的变量。
栈空间
在 Windows 中,程序栈空间不是无限的,这在调试程序时可能存在麻烦。
使用 -Wl,--stack=2147483647
可以使你的程序栈空间达到 \(2147483647\) 字节,约 \(2\text{GB}\)。
其中,-Wl
表示将命令传送到链接器,--stack
是链接器的选项,控制进程栈的大小。
如果是 Linux 系统,在终端使用 ulimit -s unlimited
。
溢出检查
-ftrapv
选项可以检测整数溢出并导致程序异常终止。
使用 g++
命令编译时,程序会将操作数保存在寄存器中,调用一个名称类似 __addvsi3
的函数,具体命名与操作符和变量类型有关。经测试,int
、long long
、__int128
都有不同的命名,说明应该都能正常检查。short
运算时没有类似行为,说明不会检查。
使用 clang++
命令编译时,程序会正常进行运算,然后使用 seto
指令检查溢出标志。不过,由于 short
运算时会使用 l
后缀的指令,不能正常检查。
以上内容来自本地测试,可能与其他环境存在出入。
这同样提醒我们,不要使用 short
类型,除非程序卡空间达到了变态的程度。
不会检查无符号整数溢出,因为后者是良定义的。