过去我曾使用-Wall和其他gcc开关来消除我参与的项目的每个编译器警告。同样,在Perl中,我总是用use strict编程并使用警告(并经常 - T也是如此)试图达到我能做到的最佳代码质量。据我所知,几年前,Perl搬运工小组努力使perl本身(Perl解释器)在gcc下干净利落地编译并启用了所有警告。显然他们觉得这对代码质量来说是一个好主意。我也明白,现在Perl的程序员已经在他们的代码中添加了更多的警告Perl :: Critic,当他们违反Damian Conway的Perl最佳实践书(以及其他来源,我相信)中发现的最佳实践时会发出警告。
我总是对我用这种方式清理的代码有一种良好的感觉,但有时我无法避免一些工作有点浪费的感觉。例如,在十多年前的我的介绍C课程中,我被教导要像这样启动我的main()函数:
void main(void) {
这是最小的,只能在您没有返回值并且没有访问您的参数时使用。它在这种情况下工作正常,但gcc警告会让你知道这个函数应该是这样的:
int main(int args, char* argv) {
我必须在当天输入几百个未使用的int args,char * argv行。我真的让我的代码变得更好,或者只是把手指缩短了吗?
现在我在Eclipse中用Java编程,我们的项目有成千上万的警告。我想清理它们。其中一些特别难以理解和消除,但我正在慢慢学习。其中一些我必须处理编译器指令来抑制警告(通常用微小的方法来分解忽略警告的不良做法),但我也找到了解决这些问题的方法。
这值得程序员的时间吗?如果你追踪每一个编译器警告,项目真的会好得多吗?
如果不出意外的话,将警告的数量减少到零似乎很好,这样严重的警告就不会在乱七八糟的时候丢失。
重复答案 0 :(得分:28)
是的,当然。警告表示代码中可能存在错误。要么你修复它,要么你应该禁用警告 - 如果你不打算采取行动,警告只是阻止你检测何时出现新的警告。
获取并保持代码无警告的最简单方法就是始终使用-Werror(Visual Studio中的/ WX)或等效代码进行编译。
答案 1 :(得分:8)
我同意所有说“全部修复”的答案,但我仍然想提出一个相反的观点:
有一些遗留系统,其中一些(许多或所有)组件没有专门的维护者,系统的大部分基本上是未知的。修复此类未知代码中的编译器警告可能需要相当多的代码(因为对于每个警告,需要理解代码及其上下文)并引入可能的错误源(某些代码取决于 on undefined行为)。由于此类遗留系统很少有大量的测试覆盖率,您甚至无法依靠测试来通知您回归。
答案 2 :(得分:7)
这值得程序员的时间吗?如果你追踪每一个编译器警告,项目真的会好得多吗?
是。即使是关于符号不匹配的微不足道的事情也会对代码生成和优化产生深远的影响。
答案 3 :(得分:7)
C中有两个兼容的main原型。
int main(void)
和
int main(int argc, char **argv)
void main(void)
在技术上并不正确,尽管某些编译器可能会支持它作为标准的扩展。
因此,在您的特定情况下,您可以使用main
的简短声明,如果符合,则不会触发警告。
答案 4 :(得分:5)
是。即使是微不足道的也值得一试。这就是原因。有些人,比如你提到的主要例子,可能不值得自己修理,但它们是合计的。从长远来看,大多数编译器警告都会为您带来直接的痛苦。它们是等待发生的错误(甚至现在发生)。为了找到它们,您需要一种简单的方法来注意它们。如果您修复了所有警告,那么每个新警告都是一个红色标记,很容易被注意到。如果你修复了所有关键问题,但只留下一些类似“主要”问题,那么你将会错过新的关键问题。
哪个更容易记住?任何警告都需要修复,或者你昨天在这个代码库中有23个不相关的警告,所以如果你看到24你需要去看看吗?
在我工作的代码库中,我们告诉编译器在所有警告上生成错误。这迫使我们修复它们并使代码保持更好的形状。如果有一个真正不值得修复的警告,总会有#pragma让它消失。这样你仍然有一条明确的失败线。
答案 5 :(得分:4)
我将在这里反对,并说可能有一些编译器警告不值得修复。示例如下:
我们有大量的代码是在Java 1.5和泛型之前编写的。它仍然有效。 Eclipse还会生成数千个关于非参数化集合的警告。实际上所有这些集合的范围都是有限的;他们永远不会破产。但是等等,你可能会问;那些不在范围内的少数集合呢?你是不是冒险在一个包含一个永远不应该进入的实例的某个地方的集合?
响应是:很多代码也没有变化。它的遗产是什么;没有新代码正在修改这些集合,并且该代码已经使用多年而没有任何问题。它仍然在我们的代码库中,如果出现错误,我们必须维护它,但在实践中,它完成了它的工作。花费必要的时间来参数化所有这些通用集合需要花费时间来完成其他所需的项目。
请注意这里的注意事项:
如果其中任何一个停止为真 - 例如,突然 突然出现的错误,我们必须进入并编辑 - 警告突然变得更有价值。 (顺便说一下,在这一点上修复它们也非常便宜;我们可以在修复错误时修复相关的块。)
答案 6 :(得分:3)
是的,这样做..
就在昨天,我为工作项目做了这件事。在删除警告时,我发现了两个问题,结果证明是真正的错误。
这是一个C项目,并在一个来源中调用了sqrt(平方根)。我收到了以下警告:
test.c:4: warning: implicit declaration of function 'sqrt'
原来,编码器忘记包含正确的头文件,并且使用整数参数调用平方根,而不是浮点数。这显然是错误的,而不是他的意图。
警告已经存在了很长一段时间,但没有人看到它,因为它在其他1000个无害警告中丢失了,只是在屏幕上滚动。 警告是有原因的。
顺便说一句 - 修正警告让我感觉...... 4个小时......与编写所有内容所花费的时间相比,这没什么。答案 7 :(得分:2)
Eclipse,IntelliJ和其他现代代码质量系统都有大量可用的警告。
清理警告是一种有用的做法,如果没有其他原因,请安静下来。您的代码可能已经存在一些真正的错误。
但是,许多警告可能都是假的。 Eclipse的一些警告就像微优化或风格挑剔一样。这意味着您的一些清理必须调整工具的设置,而不是代码更改或本地化抑制指令。
答案 8 :(得分:2)
只是添加警告,这是gnome开发人员在他的代码中使用的内容:
答案 9 :(得分:2)
确保代码编译时没有警告的另一个原因是,如果其他人*必须在将来某个时候对代码进行更改,那么一个好的起点是确保他们可以编译代码目前的形式。
但是,如果他们这样做,并看到很多警告,这些警告是否一直存在,或者他们在PC上错误地安装了编译器?
至少如果有一条规则(以及一个勾选清单上的方框,如果你使用的那个)代码必须在没有警告的情况下进行编译,那么你就避免了这种歧义。
(*其他人可能包括你未来的自我)。
答案 10 :(得分:1)
它将为编译器保存写出警告的时间,并且如果您减少代码中无意义警告的数量,则可以更轻松地查找可能存在危险的警告。 是否值得花时间去追捕每一个警告并修复它?通常不是......但是当它们显而易见并且易于修复时,或者当您需要花时间并且由于其他原因更改包含警告的逻辑时,值得修复警告。
答案 11 :(得分:1)
我的意见。是。
就像你最后说的那样。它有助于使真正的错误更加突出。
当您运行在Apache服务器上输出警告的Perl cgi脚本时,会在error.log中记录警告。为什么要浪费空间。修正警告。
此外,我认为更好地理解语言和编译器是一种学习经验。在我开始使用严格之前,我没有意识到动态范围甚至是Perl的一个特性。
答案 12 :(得分:1)
您的示例是一个完美的例证,为什么警告不应该被忽略。 void main(void)
是一个无效的原型(但int main(void)
有效!))并且您的代码可能会在某些编译器上中断。你的编译器很好地指出了这一点。
我发现几乎每个警告实际上都指向了一个真正的问题,即使我当时没有理解原因。基本上,我总是做点什么,并打算做别的事情。无论如何,这种效果可能已经实现,但只是纯粹的巧合。
将警告视为错误。存在异常(VB.NET编译器中有一个涉及未初始化的值类型),但非常罕见。如果您偶然发现其中一个例外情况,您将知道它。
答案 13 :(得分:1)
你应该总是尝试在编译时没有警告。这样,新警告就会受到关注。 (我曾经遇到的最令人沮丧的经历是2002年的AIX C ++编译器,它为代码提供了数百个警告,而这些代码甚至没有被严格模板化。)
了解每个警告的含义。在您的情况下,您应该输入标准int main()
而不是错误的void main(void)
或笨拙的int main(int argc, char **argv)
。消除你所能做的,并取消你认为可以接受的警告。
您可能不想修复所有警告。正如saua所说,有一些遗留系统,其中修复警告是非常危险的,以及像CGAL这样的复杂系统,你不想在这些系统中使用代码。在将我们的应用程序转换为64位以下运行时,我发现只能使用强制转换消除警告的情况,这可能会导致其他问题。我们压制了这个警告。