16

过去,我使用 -Wall 和其他 gcc 开关来消除我参与的项目的每个编译器警告。类似地,在 Perl 中,我总是使用 use strict 和 use 警告进行编程(通常也是 -T ) 尽量达到最好的代码质量。我知道几年前,Perl 搬运工小组努力使 perl 本身(Perl 解释器)在 gcc 下干净地编译并启用所有警告。显然,他们认为这是提高代码质量的好主意。我还了解到,现在 Perl 程序员已经使用 Perl::Critic 在他们的代码中添加了更多警告,当他们违反 Damian Conway 的 Perl Best Practices 书中的最佳实践时会发出警告(我相信来自其他来源)。

对于这样清理的代码,我总是有一种很好的感觉,但有时我无法避免有些工作有点浪费的感觉。例如,在十多年前的 C 入门课程中,我被教导要像这样启动我的 main() 函数:

void main(void) {

这是最小的,只能在您没有返回值并且没有访问您的参数时使用。在这种情况下它工作得很好,但是 gcc 警告会让你知道这个函数真的应该看起来像:

int main(int args, char* argv) {

那天我一定已经输入了几百个未使用的 int args, char* argv 行。我真的让我的代码变得更好,还是只是把我的手指磨短了?

现在我在 Eclipse 中用 Java 编程,我们的项目有数以万计的警告。我想把它们清理干净。其中一些特别难以理解和消除,但我正在慢慢学习。其中一些我不得不使用编译器指令来处理以抑制警告(通常以极小的最小方法来排除忽略警告的不良做法),但我也在寻找处理这些的方法。

这值得程序员的时间吗?如果您跟踪每一个编译器警告,项目真的会更好吗?

如果不出意外,将警告的数量减少到零似乎会很好,这样严重的警告就不会在混乱中丢失。

注意这个问题的重复

4

14 回答 14

29

当然是。警告表明您的代码可能有问题。要么你修复它,要么你应该禁用警告——如果你不打算对它采取行动,警告只是阻止你检测新警告何时出现。

获取并保持代码无警告的最简单方法是始终使用 -Werror(Visual Studio 中的 /WX)或等效项进行编译。

于 2009-02-04T16:57:23.223 回答
8

这值得程序员的时间吗?如果您跟踪每一个编译器警告,项目真的会更好吗?

是的。即使是关于符号不匹配的琐碎问题也会对代码生成和优化产生深远影响。

于 2009-02-04T16:57:53.690 回答
8

我同意所有说“全部解决”的答案,但我仍然想提出相反的观点:

有一些遗留系统,其中一些(许多或全部)组件没有专门的维护者,并且系统的大部分基本上是未知的。修复此类未知代码中的编译器警告可能需要大量代码(因为对于每个警告,都需要了解代码及其上下文)并引入可能的错误来源(某些代码取决于未定义的行为)。而且由于此类遗留系统很少有广泛的测试覆盖率,您甚至不能依靠测试来通知您回归。

于 2009-02-04T17:12:57.983 回答
7

C 中的 main 有两个兼容的原型。

int main(void)

int main(int argc, char **argv)

void main(void)在技​​术上并不正确,尽管某些编译器可能会支持它作为标准的扩展。

因此,在您的特定情况下,您可以使用一个简短的声明,main并且如果符合,它不会触发警告。

于 2009-02-04T17:01:31.187 回答
5

是的。即使是微不足道的也值得修复。这就是为什么。有些,例如您提到的 main 示例,可能不值得自己修复,但它们是总体上的。从长远来看,大多数编译器警告都会为您省去直接的痛苦。它们是等待发生(甚至现在发生)的错误。为了找到它们,您需要一种简单的方法来注意到它们。如果您修复了所有警告,那么每个新警告都是一个危险信号并且很容易注意到。如果你修复了所有的关键问题,但只留下一些像“主要”问题一样,你将错过新的关键问题。

哪个更容易记住?是否需要修复任何警告,或者您昨天在此代码库中有 23 个不相关的警告,所以如果您看到 24 个,您需要去看看吗?

在我处理的代码库中,我们告诉编译器在所有警告上生成错误。这迫使我们修复它们并使代码保持更好的状态。如果有真正不值得修复的警告,总有#pragma 让它消失。这样你仍然有一条失败的明线。

于 2009-02-04T17:03:24.973 回答
4

是的,这样做..

就在昨天,我为工作中的一个项目这样做了。在删除警告时,我遇到了两个问题,结果证明是真正的错误。

这是一个 C 项目,在一个源代码中调用了 sqrt(平方根)。我收到以下警告:

test.c:4: warning: implicit declaration of function 'sqrt'

原来,编码器忘记包含正确的头文件,平方根是用整数参数调用的,而不是浮点数。这显然是错误的,不是他的本意。

该警告已经存在了很长一段时间,但没有人看到它,因为它在刚刚滚动到屏幕上的其他 1000 个无害警告中丢失了。 警告是有原因的。

顺便说一句 - 修复警告花了我...... 4 小时......与编写所有这些东西所花费的时间相比,这算不了什么。

于 2009-02-04T17:02:02.527 回答
4

我将在这里反对包并说可能存在一些不值得修复的编译器警告。示例如下:

我们有大量在 Java 1.5 和泛型之前编写的代码。它仍然有效。Eclipse 还会生成数以千计的关于未参数化集合的警告。实际上,所有这些集合的范围都是有限的;他们永远不会破裂。但是等等,你可能会问;那少数几个不受范围限制的系列?你不是在冒着收集某个地方的风险,其中包含一个永远不应该进入那里的东西的实例吗?

回应是:很多代码也没有改变。这是传统的;没有新代码正在修改这些集合,并且该代码已使用多年而没有问题。它仍在我们的代码库中,如果出现错误,我们将不得不维护它,但实际上,它已经完成了它的工作。花必要的时间参数化所有这些通用集合将占用其他所需项目的时间。

请注意此处的警告,然后:

  • 该代码已经使用了很长时间,没有报告任何错误。
  • 该代码未进行任何实质性编辑。

如果其中任何一个不再是真的——例如,一个错误突然出现,我们必须进入并编辑——警告突然变得更值得修复(顺便说一句,此时修复它们的成本也非常低;我们可以在修复错误的过程中修复相关块。)

于 2009-02-04T17:20:37.500 回答
2

它将节省编译器写出警告的时间,并且如果您减少代码中无意义的警告数量,则更容易找到潜在的危险警告。是否值得花时间寻找每个警告并修复它?通常不会……但是当警告明显且易于修复时,或者当您出于其他原因需要花时间更改包含警告的逻辑时,值得修复警告。

于 2009-02-04T16:57:44.377 回答
2

Eclipse、IntelliJ 和其他现代代码质量系统有大量可用的警告。

清理警告是一种有用的做法,如果没有其他原因,只是为了消除噪音。您的代码可能已经有一些真正的错误。

但是,许多警告可能是虚假的。来自 Eclipse 的一些警告是诸如微优化或风格挑剔之类的东西。这意味着您的一些清理工作必须调整工具的设置,而不是代码更改或本地化抑制指令。

于 2009-02-04T17:00:35.840 回答
2

我的意见。是的。

就像你最后说的。它有助于使真正的错误更加突出。

当您在 Apache 服务器上运行输出警告的 Perl cgi 脚本时,警告会记录在 error.log 中。为什么要浪费空间。修复警告。

此外,我认为这是一种更好地理解语言和编译器的学习体验。在我开始使用 strict 之前,我没有意识到动态作用域甚至是 Perl 的一个特性。

于 2009-02-04T17:01:00.313 回答
2

您的示例很好地说明了为什么不应忽略警告。void main(void)是无效的原型(但int main(void)有效!))并且您的代码可能会在某些编译器上中断。你的编译器很好地指出了这一点。

我发现几乎每个警告实际上都指向了一个真正的问题,即使我当时未能理解原因。基本上,我总是做某事并打算做其他事情。无论如何,效果可能已经实现,但纯属巧合。

将警告视为错误。存在异常(VB.NET 编译器中有一个关于未初始化值类型的异常),但极为罕见。如果您偶然发现这些例外之一,您就会知道

于 2009-02-04T17:07:10.007 回答
2

您应该始终尝试在编译时不出现警告。这样,新的警告就会引起注意。(我在这方面最令人沮丧的经历是 2002 年的 AIX C++ 编译器,它针对没有大量模板化的代码发出了数百条警告。)

了解每个警告的含义。在您的情况下,您应该输入 standardint main()而不是不正确void main(void)或 clumsier int main(int argc, char **argv)。消除你能做的,并压制你认为可以接受的警告。

您可能不想修复所有警告。正如 saua 所说,有些遗留系统修复警告是非常危险的,而像 CGAL 这样的复杂系统,你也不想弄乱代码。在将我们的应用程序转换为在 64 位下运行时,我发现我只能通过强制转换来消除警告,这可能会导致其他问题。我们压制了那个警告。

于 2009-02-04T17:27:45.720 回答
2

只是为了添加警告,以下是 gnome 开发人员在其代码中使用的内容:

http://blogs.gnome.org/otte/2008/12/22/warning-options/

于 2009-02-04T17:42:40.963 回答
2

确保您的代码在没有警告的情况下编译的另一个原因是,如果其他人*必须在将来某个时候对代码进行更改,那么一个好的开始是确保他们可以在当前版本中编译代码形式。

但是,如果他们这样做并看到很多警告,这些警告是一直存在的,还是他们在 PC 上错误地安装了编译器?

至少如果有一个规则(如果你使用一个复选框,在清单上打勾)代码必须在没有警告的情况下编译,那么你就可以避免这种歧义。

(* 其他人可能包括你未来的自己)。

于 2009-02-04T23:14:37.987 回答