我经常听到有人说,在编译C和c++程序时,我应该“总是启用编译器警告”。为什么这是必要的?我怎么做呢?
有时我也听到我应该“把警告当作错误”。我应该吗?我怎么做呢?
我经常听到有人说,在编译C和c++程序时,我应该“总是启用编译器警告”。为什么这是必要的?我怎么做呢?
有时我也听到我应该“把警告当作错误”。我应该吗?我怎么做呢?
当前回答
我曾经在一家制造电子测试设备的大公司(财富50强)工作过。
我的团队的核心产品是一个MFC程序,多年来,它产生了数百个警告。在几乎所有的案例中都被忽略了。
当出现bug时,这简直是一场噩梦。
在那个职位之后,我很幸运地被一家新创业公司聘为第一个开发人员。
我鼓励所有构建都采用“无警告”策略,并将编译器警告级别设置为相当吵闹的级别。
我们的做法是使用#pragma warning - push/disable/pop用于开发人员确定确实没问题的代码,并在调试级别使用日志语句,以防万一。
这种做法对我们很有效。
其他回答
你一定要启用编译器警告,因为一些编译器不擅长报告一些常见的编程错误,包括以下:
初始化变量会被遗忘 从一个被错过的函数返回一个值 printf和scanf族中的简单参数与格式字符串不匹配 函数的使用没有事先声明,尽管这只在C中发生
所以这些函数可以被检测和报告,只是通常不是默认情况;所以这个特性必须通过编译器选项显式地请求。
你应该总是启用编译器警告,因为编译器经常会告诉你代码哪里出了问题。为此,您将-Wall -Wextra传递给编译器。
您通常应该将警告视为错误,因为警告通常表示您的代码有问题。然而,通常很容易忽略这些错误。因此,将它们视为错误将导致构建失败,因此您不能忽略这些错误。若要将警告视为错误,请将-Werror传递给编译器。
别着急:你不必这么做,也没有必要。-Wall和-Werror是由代码重构狂人为自己设计的:它是由编译器开发人员发明的,目的是避免在用户端编译器或编程语言更新后破坏现有的构建。特性本身并不是什么,而是关于是否破坏构建的决定。
使用与否完全取决于您的喜好。我一直在用它,因为它能帮我改正错误。
由于某些原因,c++中的编译器警告非常有用。
它可以告诉你,你可能在哪里犯了一个错误,这可能会影响你的操作的最终结果。例如,如果你没有初始化一个变量,或者如果你使用“=”而不是“==”(这只是例子) 它还允许向你展示你的代码不符合c++标准的地方。这很有用,因为如果代码符合实际标准,那么将很容易将代码移到其他平台。
一般来说,警告是非常有用的,可以告诉您代码中哪里有错误,这些错误可能会影响算法的结果,或者在用户使用您的程序时防止出现某些错误。
作为使用遗留嵌入式C代码的人,启用编译器警告有助于在提出修复时显示许多弱点和需要调查的领域。在GCC中,使用-Wall和-Wextra甚至-Wshadow变得至关重要。我不打算一一列举每一个危险,但我将列出一些已经出现的有助于显示代码问题的危险。
变量被落下
这可以很容易地指出未完成的工作和可能没有使用所有传递变量的区域,这可能是一个问题。让我们来看看一个简单的函数,它可能会触发这个:
int foo(int a, int b)
{
int c = 0;
if (a > 0)
{
return a;
}
return 0;
}
在没有-Wall或-Wextra的情况下编译它不会返回任何问题。-Wall会告诉你c从来不用:
foo.c:在函数' foo '中:
Foo.c:9:20:警告:未使用的变量' c ' (-Wunused-variable)
wextra还会告诉你参数b什么都不做:
foo.c:在函数' foo '中:
Foo.c:9:20:警告:未使用的变量' c ' (-Wunused-variable)
foo.c:7:20:警告:未使用参数' b ' [-Wunused-parameter] int foo(int a, int b)
全局变量阴影
这一点有点难,直到使用-Wshadow才显示出来。让我们修改上面的示例,只添加一个,但是刚好有一个全局变量和一个局部变量同名,这在尝试使用两者时造成了很多混乱。
int c = 7;
int foo(int a, int b)
{
int c = a + b;
return c;
}
当打开-Wshadow时,很容易发现这个问题。
Foo.c:11:9:警告:声明' c '隐藏全局声明 (-Wshadow) Foo.c:1:5:注意:阴影声明在这里
格式字符串
这在GCC中不需要任何额外的标志,但在过去它仍然是问题的根源。一个简单的函数试图打印数据,但有格式化错误,可能是这样的:
void foo(const char * str)
{
printf("str = %d\n", str);
}
这不会打印字符串,因为格式化标志是错误的,GCC会很高兴地告诉你这可能不是你想要的:
foo.c:在函数' foo '中:
Foo.c:10:12:警告:格式' %d '期望 参数类型为' int ',但参数2的类型为' const char * ' (-Wformat =)
这只是编译器可以为您进行双重检查的许多事情中的三件。还有很多其他的方法,比如使用未初始化的变量。