为啥我在写 = 而不是 == 时没有收到警告?

Posted

技术标签:

【中文标题】为啥我在写 = 而不是 == 时没有收到警告?【英文标题】:Why am I getting no warning when writing = instead of ==?为什么我在写 = 而不是 == 时没有收到警告? 【发布时间】:2016-07-21 14:24:27 【问题描述】:

由于这个无效的声明,经过数小时的努力最终确定了一个错误:

...
assert( variable = -0.5 );

这显然应该是assert( variable == -0.5 );:开发者错字。

我正在使用 Visual Studio 2015 进行编译,并且真正致力于“0-警告编译”。

这样一个糟糕而危险的语句怎么能在编译器不报告警告的情况下编译呢?是否没有我们可以启用的编译器选项来避免这种情况?

编辑:即使bool b = ( variable = -0.5 ) 也不会产生任何编译器警告

【问题讨论】:

您使用的是什么警告级别? 您是否使用 4 级编译器警告? @NathanOliver:默认 (/W3),/Wall 也不发出任何警告。 您的断言启用了吗?如果它们被禁用,则预处理器会在编译器有机会发出警告之前完全摆脱 variable = -0.5 另一个很好的例子,使用 Yoda 条件可以节省(很多?)时间。 :-) 【参考方案1】:

仅当您使用/W4 编译级别时,才会警告条件表达式中的赋值,请参阅see this。

所以我在此代码上使用在线 MSVC 编译器(我在这台 PC 上没有 VS 2015)对其进行了测试:

//Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x86

#include <iostream>
#include <cassert>
int main()
    int a;
    if (a = 2)
        std::cout << "Hello, world!\n";
    
    assert(a = 3);

这个命令行:source_file.cpp -o a.exe /EHsc /MD /W4 /I C:\boost_1_60_0 /link /LIBPATH:C:\boost_1_60_0\stage\lib 和两行警告:

Warning(s):
source_file.cpp(9) : warning C4706: assignment within conditional expression
source_file.cpp(12) : warning C4706: assignment within conditional expression

显然,QT 标头 qglobal.h 在某些配置下使用 QT_WARNING_DISABLE_MSVC(4706) 禁用此警告。

【讨论】:

@Xarn:正如 OP 中所评论的那样,即使使用 /W4 也没有警告(可能是 VS 中的错误 ...) @jpo38 你在调试中编译吗?或者更确切地说启用了断言?另一种选择是断言不够透明,编译器无法看到赋值在条件表达式中。 @jpo38:我怀疑这是一个 VS 错误。如果您已将警告设置为最大但仍未收到警告,那么您应该查看项目属性 > C\C++ > 高级 > 禁用特定警告以查看是否有人禁用了该警告。 @Xarn:正如对其他答案的评论,即使bool b = ( refSlope = -0.5 ); 也不会产生任何警告。所以assert不是问题的根本原因。 @jpo38 你真的启用了/W4 吗?在 cmets 中,您只需指定 /W3。因为我刚刚测试了这个并看到了答案(在一分钟内)。【参考方案2】:

您没有收到警告,因为它是完全合法且使用过的表达方式,例如,

while( (char c = getNextChar()) ) ...

因此,有些人在与 const 进行比较时,倾向于将 const 写在 lhs 上:

assert( -0.5 =  variable ); // this is an error
assert( -0.5 == variable ); // this is correct

请注意,当您有两个非常量要比较时,这不会扩展;此外,记住这条规则是否更容易记住 === 是有争议的。

【讨论】:

记住”这是一个纪律和培训问题,主要是...... ;-) @alk: 嗯.. 在我不明白的事情中,为什么我们不能将:= 甚至&lt;- 保持为相等,而将= 保持为相等。我使用它,我忍受它 - 每当我与非程序员交谈时,我都会说出通常的借口。为什么 = 在 K&R C 中被首选为 set-equals,除了让数学和物理方面的人感到困惑之外?【参考方案3】:

不幸的事实是,没有简单的方法可以通过静态时间分析来避免这种错误。考虑一下:

assert(var = possiblyUnsafeOp());
assert(var.otherOp() == something);

第一行证明可能UnsafeOp()返回一个非null,写测试时不能称为错误。

【讨论】:

这是一个可怕的想法,因为断言在发布版本中是无用的。 是的,这是很糟糕的代码。但是,这只是为了说明有人可能会采取哪些措施来防止实际的警告系统捕捉到东西。【参考方案4】:

这种模式对于遍历列表直到找到 0 是有用的,所以人们可能会故意这样写,这就是为什么不生成警告的原因。例如:

while(int a = nextElem())
  //Do something with a

代替:

int a = nextElem();
while(a)
  //Do something with a
  a = nextElem();

或者只有在函数返回非 0 时才做某事,这通常意味着错误

if(int res = myFunction())
  //Do something only if non-0

在您的情况下,变量被分配-0.5,并且当它被强制转换为断言期望它被钳制为0的int时。您可以通过更改检查的位置来避免这种情况,因为-0.5 = variable无效(但是-0.5 == variable 是),所以除非你把两个 = 符号放在一起,否则它不会编译。

【讨论】:

【参考方案5】:

您没有任何警告,因为断言测试了分配,并且它有效。 正如blobonat所说,更安全的代码是:-0.5 = variable

【讨论】:

断言不是问题的根本原因。即使bool b = ( refSlope = -0.5 ); 也不会产生警告。 是的,我谈论断言是因为它是他的代码中使用的。断言中的矫揉造作是问题的根源。【参考方案6】:

这种行为实际上可以派上用场,如果你想使用 assert 评估一些复杂的语句但你必须事先做一些赋值怎么办?在这种情况下(现在想不出一个有效的例子,但我记得用这种方式)你可以这样做:

assert(variable = -0.5, (do something with variable));

这显然不能在发布版本中使用,但对复杂的断言很有帮助。

【讨论】:

这是一个可怕的想法,因为断言在发布版本中是无用的。 为什么所有的投票都被否决了?我没有说你应该在发布时使用它,你可以用它来做复杂的断言,这有什么问题? @monkeyStix 就像其他两个已删除的答案一样,这忽略了问题的重点:鉴于编译器警告if (i = 0) 之类的东西,为什么他们不警告更狡猾的assert(i = 0) ? @Baum mit Augen 虽然我自己不喜欢它,但对于一些在 if 和 while 中进行分配的人来说是常见的做法,我只是在解释为什么默认行为是不警告用户。

以上是关于为啥我在写 = 而不是 == 时没有收到警告?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我在使用 UPDATE 代码时没有收到 No_data_found 错误?

为啥我在 iOS13.2 中加载 WKWebView 时收到控制台警告:[Process] kill() 返回意外错误 1?

我将 QPixmap 传递给 QAbstractButton::setIcon 而不是 QIcon,但我没有收到错误...为啥?

为啥我在 C 中收到警告“分段错误,核心转储”

为啥我在我的设备上收到成功注册消息,而服务器数据库没有变化?

mingw g ++以错误的语言发出警告(德语而不是英语)