为什么要始终启用编译器警告?

n. *_* m. 292 c c++ warnings c++-faq compiler-warnings

我经常听到,在编译C和C ++程序时,我应该“始终启用编译器警告”。为什么这是必要的?我怎么做?

有时我也听说我应该“将警告视为错误”。我是不是该?我怎么做?

n. *_* m. 334

为什么要启用警告?

C和C ++编译器在报告一些常见的程序员的失误出了名的坏默认情况下,如:

  • 忘记初始化变量
  • 忘记return函数中的值
  • printfscanf系列中的参数与格式字符串不匹配
  • 使用函数而无需事先声明(仅C)

这些可以被检测和报告,通常不是默认情况下;必须通过编译器选项显式请求此功能。

如何启用警告?

这取决于您的编译器。

微软的C和C ++编译器理解开关一样/W1/W2/W3/W4/Wall。至少使用/W3/W4/Wall可能对系统头文件发出虚假警告,但是如果您的项目使用这些选项之一进行了正确的编译,则应这样做。这些选项是互斥的。

大多数其他编译器理解像选项-Wall-Wpedantic-Wextra-Wall是必不可少的,所有其他建议都被推荐(请注意,尽管名称如此,但-Wall仅启用最重要的警告,而不是全部警告)。这些选项可以单独使用,也可以一起使用。

您的IDE可能有一种从用户界面启用这些功能的方法。

为什么将警告视为错误?它们只是警告!

编译器警告表示您的代码中可能存在严重的问题。上面列出的问题几乎总是致命的。其他可能会或可能不会,但是您希望编译失败,即使事实证明这是一个错误的警报。调查每个警告,找到根本原因,然后加以解决。如果出现错误警报,请解决它-即,使用其他语言功能或结构,以便不再触发警告。如果事实证明这很难,请逐个禁用该特定警告。

您不希望仅将警告作为警告,即使它们都是错误警报。对于发出警告的总数少于7个的非常小的项目,这可能是可以的。不要这样 只要使您的所有项目都能干净地编译即可。

请注意,这适用于程序开发。如果您以源代码形式向世界发布项目,那么最好不要-Werror在已发布的构建脚本中提供或提供等效的版本。人们可能会尝试使用不同版本的编译器或完全不同的编译器来构建您的项目,这可能会启用一组不同的警告。您可能希望他们的建造成功。始终启用警告仍然是一个好主意,以便看到警告消息的人可以向您发送错误报告或补丁。

如何将警告视为错误?

再次使用编译器开关完成此操作。/WX适用于Microsoft,大多数其他人使用-Werror。无论哪种情况,如果产生任何警告,编译都将失败。

  • 我之所以发布此问题与解答,是因为我厌倦了告诉人们启用警告。现在,我可以将他们指向此处(或者,如果我的心情特别邪恶,请以欺骗的方式结束他们的提问)。欢迎您改善此答案或添加您自己的答案! (103认同)
  • 对于遵循默认构建说明的人来说,将警告视为错误的不利方面是,随着编译器添加新警告,您的代码会腐烂。下载您的代码并在将来尝试构建它的用户可能无法这样做,因为他们的编译器太新了,并发出一些额外的括号或您的编译器不关心的警告。遇到错误的用户不对您的代码或构建系统负责,也不知道如何关闭将警告视为错误并实际构建项目的方法。 (20认同)
  • 您还可以使用[clang的-Weverything](https://clang.llvm.org/docs/UsersManual.html#cmdoption-weverything) (16认同)
  • @interfect是的,这发生在我身上几次。没关系 如果您选择使用从未经过测试的编译器来构建*未维护*的软件,那么,您最好准备自己进行一些维护。 (15认同)
  • 我要添加的唯一修饰符是某些警告可能对您的应用程序没有帮助。(我看到过警告,编译器在结构中的元素之间添加了2个字节的填充。该应用程序用于原型设计,因此一点浪费的内存不会困扰我们。)将所有警告视为错误,然后仅在以下情况下禁用警告:您知道该警告为何无济于事。 (8认同)
  • @interfect软件发行版本质上不仅是软件本身的产品,而且还是构建时间和运行时环境的产品。尝试使用不同的编译器构建相同代码的人正在修改项目,并继承它们造成的任何麻烦。这不是阻止我们在原始版本中使用良好保护的原因。(如果新的构建者真的相信警告不是什么大问题,他们可以自行更改构建设置。) (5认同)
  • 我要补充一点,`-Werror`和表兄弟在CI中很有意义,但在日常开发中并没有那么多。例如,一般来说,警告未使用的参数是合理的,但是当我添加一堆新功能并草绘一般结构时,不需要用它来停止编译。 (4认同)
  • @JMAA语言错误通常报告为没有任何特殊标志的错误。 (3认同)
  • “众所周知,C和C ++编译器不善于报告一些常见的程序员错误,例如:” _实际上,它们非常擅长于此。那就是警告_are_。您是说“众所周知,C和C ++语言不会将这些错误变成硬错误”吗? (3认同)
  • 我要补充一点,您还应该努力消除*尽可能多的警告,甚至是“无害的”警告,这就是原因。假设您有几十条警告,您知道这些警告无关紧要。您习惯于忽略它们,它们每次都会发生。它们开始堆积,但您不在乎,因为您每次都看到很多“无害”警告。现在又出现了另一个实际上是严重的警告。您能立即找到它吗?还是会消失在您自己一直忽略的所有杂音之中? (2认同)
  • 对于 MSVC,经常使用 `-Wall` 进行编译通常很好,但我个人不建议将其与 `-WX` 结合使用。它启用了一些警告,可以捕获微妙的小错误,例如“嘿,这个类有一个虚拟函数,但是您忘记将 dtor 设为虚拟!”,而且还提供信息消息“警告”,例如“嘿,我优化了它,因为您从未调用过它”它!” 或者“嘿,我没有内联这个!” (2认同)
  • 我认为将警告选择性地处理为错误是一个好主意:例如-Werror = return-type -Werror = implicit-function-declaration。即使对于已发布的代码版本,这也可能很好。 (2认同)

Ste*_*mit 91

众所周知,随着HLL的发展,C是一种相当底层的语言。尽管C ++似乎比C语言要高级得多,但它仍然具有许多特质。这些特征之一就是这些语言是由程序员设计的,是为程序员而设计的,尤其是那些知道自己在做什么的程序员。

[对于此答案的其余部分,我将重点介绍C。我会说的大多数内容也适用于C ++,尽管可能不那么适用。尽管正如Bjarne Stroustrup所说的那样,“ C使脚上的射击变得容易; C ++使其更难,但是当您这样做时,它会使您的整个腿发疯。” ]

如果您知道自己在做什么- 真的知道自己在做什么-有时您可能必须“违反规则”。但是大多数时候,我们大多数人都会同意,良好的规则会让我们所有人摆脱困境,并且大胆地始终违反这些规则是一个坏主意。

但是在C和C ++中,您可以做很多令人惊讶的事情,这些都是“坏主意”,但并不是形式上的“违规”。有时在某些情况下,这是个坏主意(但在其他时候可能是有道理的);有时,几乎所有时间他们都是一个坏主意。但是传统上一直不对这些事情发出警告-因为再次假设,程序员知道自己在做什么,没有正当的理由他们就不会做这些事情,他们会被一堆烦恼不必要的警告。

但是当然,并不是所有的程序员都真正知道自己在做什么。尤其是,每个C程序员(无论经验如何)都经历了成为新手C程序员的阶段。甚至有经验的C程序员也会变得粗心和犯错。

最后,经验表明,不仅程序员确实会犯错误,而且这些错误会带来真正的严重后果。如果您犯了一个错误,并且编译器没有警告您,并且由于某种原因程序不会立即崩溃或执行明显错误的操作,那么该错误可能会在那里潜伏,隐藏,有时长达数年,直到导致一个真正的大问题。

因此,事实证明,在大多数情况下,警告毕竟是个好主意。即便是有经验的程序员也已经学会(实际上,“ 特别是有经验的程序员已经学会”),总的来说,警告往往弊大于利。每次您故意做错了事而警告是令人讨厌的事,您至少有十次无意中做了错事,而警告使您免于进一步的麻烦。当您确实想做“错误”的事情时,大多数警告可以禁用或解决几次。

(这样的“错误”的一个典型的例子是测试if(a = b)在大多数情况下,这是一个错误,这几天警告它,大多数编译器- 。有些甚至默认但是,如果你真的想同时分配ba和试验结果,您可以通过键入来禁用警告if((a = b))。)

第二个问题是,为什么要让编译器将警告视为错误?我会说这是由于人的天性,特别是说“哦,那只是一个警告,并不是那么重要,我稍后再整理”的反应太简单了。但是,如果您是拖延症患者(我不知道您是什么,但我是一个糟糕的拖延症患者),则很容易将清除工作推迟到根本,而且-如果您养成了无视警告的习惯,在您忽略的所有消息之中,越来越容易错过坐在那里的重要警告消息,却未被注意。

因此,要求编译器将警告视为错误,这是您可以解决这个人为错误的小技巧。

就我个人而言,我不太坚持将警告视为错误。(实际上,老实说,我可以说我实际上从未在“个人”编程中启用该选项。)但是,您可以确定我在工作时启用了该选项,在我们的样式指南中(写道)要求其使用。我想说-我怀疑大多数专业的程序员都会说-任何不将警告视为C错误的车间都是不负责任的行为,没有遵循公认的行业最佳实践。

  • “知道他们在做什么的程序员”-大声笑;如果我见过一个“没有真正的苏格兰人”谬论:) (8认同)
  • 问题是,最有经验的程序员会启用大多数(如果不是全部)警告。如果他们确实想使用诸如`if(re(returnCodeFromFoo = foo(bar))`)之类的东西,那么他们会添加注释并关闭警告(以便维护程序员在4年后查看它时,他/她将意识到就是说,代码是有意的。也就是说,我与一个在(在Microsoft C ++领域中)坚持使用/ Wall并把警告视为错误的人一起工作才是可行的方法。嗯,不是(除非您想要放入很多抑制评论)。 (4认同)
  • @Dancrumb哈哈back atcha。我永远不确定我是否理解[No true Scotsman](https://en.wikipedia.org/wiki/No_true_Scotsman)谬论,但是我喜欢它,所以这对我来说将是一个很好的练习。我猜这里的应用程序是这样的:“没有C程序员会写`if(a = b)`,因此我们不需要警告它。” (然后,有人会列出由该特定错误导致的10种已发布产品中的10个严重错误的清单。)“好吧,没有*有经验的* C程序员会写这个……” (2认同)
  • @SteveSummit但具有*真正*经验丰富的C程序员可以编写`if(returnCodeFromFoo = foo(bar))`并表示其含义,以便在一处捕获并测试代码(假设foo的* only *目的是为了副作用!)*真正地*经验丰富的程序员可能知道这不是一种好的编码风格,这是关键所在;) (2认同)
  • 作为一个不*每天*写代码的人,但是当我*不*做*它往往是裸露的东西(通常是在我自己设计的板上)时,我发现警告非常宝贵。当将值填充到内部寄存器中时(以DMA描述符位置为例),有关转换为指针的警告意味着我进行了强制转换以清除警告。不会有错误,但是如果其他人(甚至我自己!)在几个月内拿起该代码,那很可能会造成混乱。此外,我还将无警告规则应用到我的CAD工具的输出中。 (2认同)
  • 就像一个简单的可处理C废话的例子一样,上周我有一个循环没有终止,发现这是由于打字错误造成了大约2像素的差异:`for(int i = 0; i < 20,i ++)`看到了吗?那是逗号,而不是分号。逗号是返回右侧表达式值的“运算符”,而++不会在很长时间内返回0。完全合法的可编译代码。 (2认同)
  • 现代编译器中的警告之前有 lint。必须每天甚至更频繁地运行该工具,因为那些较旧的编译器几乎没有可用的“警告”(特别是在各种 Unix boxen 上)。正如亨利·斯宾塞 (Henry Spencer) 在 C 程序员的 10 条戒律(注释版)中所说的那样,“*对以前从未被检查过的程序进行去绒通常是对马厩的清理,就像你不希望对你最大的敌人那样。*” (2认同)
  • @PeterSmith我想提到“lint”。撇开哲学、功能分离问题不谈,当然还有一个非常实际的动机,就是拥有一个七遍编译器(“cpp”、“c0”、“c1”、“c2”、“as”、 `ld`、`lint`):PDP​​-11 的 64k 地址空间。最终,“gcc”人员宣称将“lint”作为单独的程序是错误的,他们打算在编译器本身中构建完整的、类似“lint”的功能——而且他们大多这样做了,除非你必须要求大多数这些警告中,默认情况下它们是不打开的。因此这个问题。 (2认同)

Cor*_*ica 37

警告包括一些最熟练的C ++开发人员可以融入应用程序的最佳建议。他们值得保持。

C ++是一种图灵完整的语言,在很多情况下,编译器必须简单地相信您知道自己在做什么。但是,在许多情况下,编译器可以意识到您可能不打算编写自己编写的内容。一个典型的例子是与参数不匹配的printf()代码,或传递给printf的std :: strings(这对我而言从来没有!)。在这些情况下,您编写的代码不是错误。这是一个有效的C ++表达式,带有可让编译器执行的有效解释。但是编译器有很强的直觉,您只是忽略了现代编译器易于检测的内容。这些是警告。对于编译器而言,它们是显而易见的事情,因为您可能会使用C ++的所有严格规则,而这些规则可能已经被您忽略了。

关闭或忽略警告就像选择忽略那些比您熟练的人提供的免费建议。这是在胡贝里斯上的一课,当您太靠近太阳飞行并且翅膀融化或发生内存损坏错误时,该课程就会结束。在这两者之间,我每天都会从天上掉下来!

“将警告视为错误”是这种理念的极端版本​​。这里的想法是,您解决编译器给您的每条警告-您听取每条免费建议,并采取相应措施。对于您来说,这是否是一个好的开发模型取决于团队和正在开发哪种产品。这是和尚可能会采取的禁欲法。对于某些人来说,它很棒。对于其他人则不是。

在我的许多应用程序中,我们都不将警告视为错误。我们这样做是因为这些特定的应用程序需要在具有不同年龄的多个编译器的多个平台上进行编译。有时,我们发现实际上不可能在不将警告变成另一平台的警告的情况下将警告固定在一侧。所以我们只是小心。我们尊重警告,但我们不会向后弯腰。

  • 图灵完善的C ++与此有关。许多语言正在完善,如果您做错了事,请不要相信您。 (11认同)
  • @KamiKaze每种语言都会有惯用的错误(例如Java不能阻止您编写不一致的“等于” /“ hashCode”),这是报告的实现质量问题。 (3认同)
  • @KamiKaze图灵完整性位用于表明在某些情况下编译器无法证明您的代码将无法按计划工作。这很重要,因为编译器不能使所有“错误”的代码都变成错误。错误只能保留给语言设计者确定总是“错误”的行为。(通常是因为它导致不一致的路径)。 (2认同)
  • 这也指出了“所有警告都是错误”的挑战。从设计上讲,警告是更多机会,会触发一些可能正确的代码,以换取更频繁地触发错误的代码。将警告作为错误会导致您无法使用全部语言的功能。 (2认同)
  • 但是,总的来说,程序员需要一种比“安全”功能更多的语言。我们需要一种语言来完成我们认为要执行的操作。因此,警告仍然很重要,因为我们希望计算机执行的实际操作是语义类。编译器可以通过定义“不正确”或“不安全”来选择它,但是最后您仍然拥有程序员希望程序执行的行为的超类。警告有助于缩小超类的范围。 (2认同)

小智 18

处理警告不仅使代码更好,而且使您成为更好的程序员。警告会告诉您今天对您来说似乎很少的事情,但是有一天,这种坏习惯会再次出现并咬住您的头。

使用正确的类型,返回该值,评估该返回值。花时间思考“在这种情况下,这真的是正确的类型吗?” “我需要退货吗?” 还有大个子 “此代码在未来10年内是否可以移植?”

首先养成编写无警告代码的习惯。


Jos*_*iah 16

其他答案很好,我不想重复他们所说的话。

尚未正确提及的“为什么启用警告”的另一方面是,它们在代码维护方面有很大帮助。当您编写一个规模很大的程序时,就不可能一次把整个事情都牢记在心。通常,您有一个正在积极编写和考虑的功能,或者可能在屏幕上可以引用的一个文件或三个功能,但是该程序的大部分存在于后台的某个地方,因此您必须相信它继续工作。

发出警告,并使其充满活力,并尽可能多地出现在您的脸上,可以帮助您警告您是否更改了某些内容而导致看不到的麻烦。

以clang警告为例-Wswitch-enum。如果您在枚举上使用开关并且错过了可能的枚举值之一,则会触发警告。您可能会认为这是一个不太可能犯的错误:您可能至少在编写switch语句时查看了枚举值列表。您甚至可能拥有一个为您生成切换选项的IDE,不留任何人为错误的余地。

当六个月后,您向枚举添加另一个可能的条目时,此警告便真正产生了。同样,如果您正在考虑所涉及的代码,则可能会很好。但是,如果此枚举用于多种不同目的,并且是您需要额外选择的目的之一,则很容易忘记更新6个月未触及的文件中的开关。

您可以以与自动化测试用例相同的方式来考虑警告:它们可以帮助您确保代码合理并在您首次编写代码时就做您需要的事情,但是它们可以帮助您确保对代码的理解。在生产时不断做您需要的事情。区别在于,测试用例仅适用于您的代码要求,而您必须编写它们,而警告则几乎适用于几乎所有代码的明智标准,并且警告由编写编译器的boffins慷慨地提供。

  • 他们帮助维护的另一种方式是,当您查看别人的代码时,无法分辨副作用是否是故意的。启用警告后,您知道他们至少知道此问题。 (9认同)

gsa*_*ras 13

不固定的警告迟早导致代码中的错误


例如,调试分段故障需要程序员跟踪故障的根源(原因),该故障根源通常位于代码中比最终导致分段故障的行更靠前的位置。

非常典型的原因是编译器发出了您忽略的警告的行,而导致分段错误的行最终导致了错误的行。

解决警告会解决问题。.经典!

上面的演示。考虑以下代码:

#include <stdio.h>

int main(void) {
  char* str = "Hello world!";
  int idx;

  // Colossal amount of code here, irrelevant to 'idx'

  printf("%c\n", str[idx]);

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

当使用传递给GCC的“ Wextra”标志进行编译时,会得到:

main.c: In function 'main':
main.c:9:21: warning: 'idx' is used uninitialized in this function [-Wuninitialized]
    9 |   printf("%c\n", str[idx]);
      |                     ^
Run Code Online (Sandbox Code Playgroud)

仍然可以忽略并执行代码。.然后,我将见证一个“巨大的”分段错误,就像我的IP Epicurus教授曾经说过的那样:

分段故障

为了在现实世界中进行调试,我们将从导致细分错误的那一行开始,并尝试追踪原因的根源。他们将必须寻找在这巨大数量之内i和之str内发生的事情。那里的代码...

直到有一天,他们发现自己处于idx未初始化使用状态,因此它具有垃圾值,这导致对字符串(方式)的索引超出其范围,从而导致分段错误。

如果他们没有忽略警告,他们将立即发现该错误!

  • 要您的标题:不一定。例如,一条警告建议在实际上不需要括号的公式中使用括号,该括号指出了永远不会导致错误的非问题。给定编程语言中的运算符优先级不变。曾经 (4认同)
  • @MarcvanLeeuwen您引用的实例可能会出错,例如,如果不记得运算符优先级的程序员稍微修改了公式,例如。该警告告诉您:“某人有时可能不清楚,请加上一些括号以使其更清楚”。尽管必须同意原始帖子的标题并不总是正确的。 (4认同)
  • 如果您遇到分段错误,那么您很幸运。如果你不太幸运,你可能会碰巧在测试中遇到“idx”值(如果预期值为 0,则不太可能),并且实际上碰巧指向一些永远不应该打印的敏感数据部署时。 (2认同)

Dmi*_*yev 12

将警告视为错误只是自律的一种手段:您正在编译一个程序来测试该闪亮的新功能,但是直到修复了草率的零件之后,您才能这样做。没有Werror提供其他信息,它只是非常明确地设置了优先级:

在解决现有代码中的问题之前,请勿添加新代码

真正重要的是心态,而不是工具。编译器诊断输出是一个工具。MISRA(用于嵌入式C)是另一种工具。使用哪一个都没有关系,但是可以说编译器警告是您可以获得的最简单的工具(只需设置一个标志),并且信噪比非常高。因此,没有理由使用它。

没有工具是绝对可靠的。如果您写的话const float pi = 3.14;,大多数工具不会告诉您您定义了吗?精度低下可能会导致问题。if(tmp < 42)即使众所周知,给变量赋予无意义的名称并使用幻数是在大型项目中造成灾难的一种方式,大多数工具也不会引起人们的注意。必须了解,编写的任何“快速测试”代码都只是这样:一个测试,在继续执行其他任务之前必须正确进行测试,同时仍然要看到它的缺点。如果您按原样保留这些代码,那么在花费两个月的时间添加新功能后进行调试将变得非常困难。

一旦进入正确的思维模式,就没有必要使用了Werror。将警告作为警告可以使您做出明智的决定,是继续运行您将要启动的调试会话还是有意义的,还是先中止它并首先修复警告。

  • 不管是好是坏,Rust的“ clippy” linting工具实际上会警告常量“ 3.14”。它实际上是[文档中的示例](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant)。但是正如您可能从名称中猜测的那样,`clippy`以提供积极帮助而自豪。 (3认同)

Dom*_*Dom 8

作为使用旧式嵌入式C代码的人,启用编译器警告有助于显示很多弱点和提出修复建议时需要研究的领域。在GCC利用-Wall-Wextra,甚至-Wshadow已经成为非常重要的。我不会一一列举所有危害,但会列出一些弹出的提示,以帮助显示代码问题。

留下的变量

这很容易指出未完成的工作和可能没有利用所有传递变量的领域。让我们看一个可能触发此操作的简单函数:

int foo(int a, int b)
{
   int c = 0;

   if (a > 0)
   {
        return a;
   }
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

仅在不使用-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;
}
Run Code Online (Sandbox Code Playgroud)

启用-Wshadow时,很容易发现此问题。

foo.c:11:9:警告:'c'声明掩盖了全局声明[-Wshadow]

foo.c:1:5:注意:此处有阴影的声明

格式化字符串

这在gcc中不需要任何额外的标志,但是在过去,它仍然是问题的根源。尝试打印数据但有格式错误的简单函数如下所示:

void foo(const char * str)
{
    printf("str = %d\n", str);
}
Run Code Online (Sandbox Code Playgroud)

由于格式标记错误,因此无法打印字符串,gcc会很高兴地告诉您这可能不是您想要的:

foo.c:在函数“ foo”中:

foo.c:10:12:警告:格式'%d'期望类型为'int'的参数,但是参数2的类型为'const char *'[-Wformat =]


这些只是编译器可以为您仔细检查的许多事情中的三件事。还有许多其他方法,例如使用其他人指出的未初始化变量。

  • 在嵌入式世界中,让我最担心的警告是“可能丢失精度”和“签名与未签名之间的比较”警告。我发现很难掌握有多少“程序员”忽略了这些(实际上,我不确定自己为什么不是错误) (7认同)
  • 在后一种情况下,@ Mawg,我相信它不是错误的主要原因是`sizeof`的结果是无符号的,但是默认的整数类型是有符号的。结果类型为size_t通常用于与类型大小有关的任何事情,例如对齐或数组/容器元素计数,而除非另有说明,否则通常将整数用作“ int”需要”。考虑到有多少人因此被教导使用int遍历他们的容器(将int与size_t进行比较),使它出错将破坏一切。; P (3认同)

小智 7

编译器警告是你的朋友(不是喊叫,大写强调)。

我在旧版 Fortran-77 系统上工作。编译器告诉我有价值的事情:子例程调用中的参数数据类型不匹配,在将值设置到变量之前使用局部变量,如果我有一个未使用的变量或子例程参数。这些几乎总是错误。

避免长篇幅:当我的代码干净利落地编译时,97% 可以正常工作。与我一起工作的另一个人在编译时关闭所有警告,在调试器中花费数小时或数天,然后要求我提供帮助。我只是用警告编译他的代码,然后告诉他要修复什么。


JL2*_*210 6

您应该始终启用编译器警告,因为编译器通常会告诉您代码有什么问题。为此,您需要传递-Wall -Wextra给编译器。

您通常应该将警告视为错误,因为警告通常表示您的代码有问题。但是,通常很容易忽略这些错误。因此,将它们视为错误会导致构建失败,因此您不能忽略这些错误。要将警告视为错误,请传递-Werror给编译器。


Jos*_*hua 6

这是对C的一个具体答案,为什么这对C比对其他任何东西都重要。

#include <stdio.h>
int main()
{
   FILE *fp = "some string";
}
Run Code Online (Sandbox Code Playgroud)

此代码编译时带有警告。C 语言中的警告几乎是地球上所有其他语言中的(应该是)错误(汇编语言除外)。C 语言中的警告几乎总是伪装成错误。警告应固定,而不是禁止显示。

gcc,我们这样做gcc -Wall -Werror

这也是某些MS非安全API警告的高度保证的原因。大多数使用C语言进行编程的人都已经学会了将警告视为错误的艰难方法,而这些东西似乎不是同一种东西,并且需要不可移植的修复程序。


Jim*_*xas 6

我曾经在一家制造电子测试设备的大型(财富 50 强)公司工作。

我小组的核心产品是一个 MFC 程序,多年来,它产生了数以百计的警告。在几乎所有情况下都被忽略了。

当出现错误时,这是​​一个可怕的噩梦。

在那个职位之后,我有幸被聘为一家新创业公司的第一位开发人员。

我鼓励所有构建都采用“无警告”策略,编译器警告级别设置为非常嘈杂。

我们的做法是使用#pragma warning - push/disable/pop 用于开发人员确定非常好的代码,以及调试级别的日志语句,以防万一。

这种做法对我们很有效。


Fiz*_*k26 5

由于某些原因,C++ 中的编译器警告非常有用。

1 - 它允许向您展示您可能犯的错误,这些错误会影响您操作的最终结果。例如,如果你没有初始化一个变量,或者如果你把“=”而不是“==”(只有例子)

2 - 它还允许向您展示您的代码不符合 C++ 标准的地方。这很有用,因为如果代码符合实际标准,则很容易将代码移动到其他平台中。

通常,警告非常有用,可以向您显示代码中的哪些错误会影响算法的结果或防止用户在使用您的程序时出现错误。


小智 5

警告是等待发生的错误。因此,您必须启用编译器警告并整理代码以删除任何警告。


小智 5

忽略警告意味着您留下了草率的代码,这不仅可能在将来给其他人带来问题,而且会使您不太注意重要的编译消息。编译器输出越多,任何人都会注意到或打扰的越少。越干净越好。这也意味着你知道你在做什么。警告是非常不专业、粗心和危险的。