搬运 - GCC 更多编译警告

> 原文 Codeforces By andreyv
不完全翻译原文,但是大多数内容来自原文


对于大多数 OIer,GCC/G++ 编译选项是比较常用的,比如 -O2 开启 O2 优化、-Wl,--stack=xxx 扩栈之类的……

但是 GCC 编译器有一个缺陷,它默认“所有程序员编写的代码都是正确的”。事实上,一些不经意犯的小错误常常会让我们花费很久的时间调试。

Part1. 初识 -Wall

对于这一点,GCC开发者写了这样一个编译选项 —— 经常会用到的编译选项 -Wall,是我觉得最好用的编译选项!它可以分析一些可能错误的代码,并给出 [Warning] 提示,比如:

1
2
long long a=1ll<<60;
printf("%d",a);

这个程序如果不开 -Wall,编译器并不会报错,然而显然是不符合我们的意思的。如果开了 -Wall,编译信息中就会出现:

[Warning] format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long long int’ [-Wformat=]

这只是 -Wall 的一个功能,它还能检测:

  1. scanf/printf 中参数与占位符数量不等:

    1
    2
    3
    4
    5
    printf("%d",1,2);
    /*
    显示:
    [Warning] too many arguments for format [-Wformat-extra-args]
    */
  2. 没有使用的局部变量(如果你定义了一个局部变量,但是从来没有使用),显示

    1
    [Warning] unused variable 'b' [-Wunused-variable]
  3. 调用未赋值的局部变量,显示

    1
    [Warning] 'a' is used uninitialized in this function [-Wuninitialized]
  4. 调用了变量但是没有进行操作(有时候zz就忘了打运算符)比如想打 cnt++;,然后只写了 cnt;
    会显示:

    1
    [Warning] statement has no effect [-Wunused-value]
  5. 好像还有一些奇怪的东西……

Part2. 深入了解 GCC 编译警告

以下内容多来自原文,有删改

  1. -pedantic -std=...,随着 C++ 的不断翻新,C++98 到 C++17 的差别是非常大的;

    为了增强不同版本的兼容性,有一些较新版本的写法在旧版本上编译也会判为正确。但是考试的时候,编译一般是比较严格的,就可能发生 CE 的惨案……

    有了这行命令会发生什么?比如下面这种写法在 C++11 及以上的版本是支持的,但是 C++98 并不支持,但是编译器并不认为错误:

    1
    2
    3
    4
    5
    6
    7
    #include<bits/stdc++.h>
    using namespace std;
    struct NODE{int x;}n;
    int main(){
    n=(NODE){1};
    return 0;
    }

    如果加上 -pedantic -std=c++98,就会警告:

    1
    [Warning] ISO C++ forbids compound-literals [-Wpedantic]
  2. -Wshadow,也是非常有用了 —— 用于警告变量重名,比如:

    1
    2
    3
    4
    int n;
    int main(){
    int n=1;
    }

    会警告:

    1
    [Warning] declaration of 'n' shadows a global declaration [-Wshadow]
  3. -Wfloat-equal,C++ 的 double 有精度误差,因此很少会用 a==b 来判断两个 double 变量相等,而是用 ABS(a-b)<EPS。加上这条命令,如果你用了 == 判断 double 变量相等,会警告:

    1
    [Warning] comparing floating point with == or != is unsafe [-Wfloat-equal]
  4. -Wconversion警告运算过程中变量的类型转换,这些运算往往是隐性的 —— 比如一个 long long 乘上 intint 会被转成 long long。然而这些转换是我们不知道的,加上这条命令可以让它显示出来,比如:

    1
    2
    long long a=1ll<<40;
    int x=a*23;

    警告:

    1
    [Warning] conversion to 'int' from 'long long int' may alter its value [-Wconversion]

以上就是在 OI 中比较常用的,那些难记住的或与 OI 无关的就没有再搬运了;

reader 们可以在文章顶部找到原文的超链接,顺便在 Codeforces 上给原博主点个赞~


The End

Thanks for reading!

0%