简体   繁体   English

为什么在写=而不是==时没有收到警告?

[英]Why am I getting no warning when writing = instead of ==?

Struggled during hours to finally identify a bug due to this invalid statement: 由于以下无效声明,经过数小时的努力,他们终于找到了一个错误:

...
assert( variable = -0.5 );

This should obviously be assert( variable == -0.5 ); 显然这应该是assert( variable == -0.5 ); : developer typo. :开发人员错字。

I'm compiling with Visual Studio 2015, and really work on having a "0-warning compilation". 我正在使用Visual Studio 2015进行编译,并且确实在进行“ 0警告编译”。

How could such a bad and dangerous statement compile with no warning being reported by the compiler? 在没有编译器报告的任何警告的情况下,如何编译这样一个糟糕而危险的语句? Is there no compiler option we can enable to avoid this? 我们是否可以启用编译器选项来避免这种情况?

Edit : Even bool b = ( variable = -0.5 ) does not produce any compiler warning 编辑 :甚至bool b = ( variable = -0.5 )不会产生任何编译器警告

Assignments within conditional expressions are only warned against if you are using /W4 compilation level, see see this . 仅在使用/W4编译级别时才警告条件表达式中的赋值,请参见this

So I tested it using an online MSVC compiler (I don't have VS 2015 on this PC) on this code: 因此,我在此代码上使用在线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);
}

And this command line: source_file.cpp -o a.exe /EHsc /MD /W4 /IC:\\boost_1_60_0 /link /LIBPATH:C:\\boost_1_60_0\\stage\\lib and both lines warned: 而此命令行为: source_file.cpp -o a.exe /EHsc /MD /W4 /IC:\\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

Apparently a QT header qglobal.h disables this warning using QT_WARNING_DISABLE_MSVC(4706) under certain configurations. 显然,在某些配置下,QT标头qglobal.h使用QT_WARNING_DISABLE_MSVC(4706)禁用了此警告。

You're not getting a warning because it's a completely legal and used expression, eg, 您没有收到警告,因为它是完全合法且使用过的表达方式,例如,

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

Some people therefore, when comparing to a const, tend to write the const on the lhs: 因此,有些人在与const进行比较时,倾向于将const写入lhs:

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

Note that this does not scale to when you have two non-consts to compare; 请注意,当您有两个要比较的非常量时,这不会缩放。 also, it's arguable whether remembering this rule is any easier to remembering == vs. = . 同样,记住这个规则是否更容易记住== vs. =是有争议的。

The unfortunate fact is that there is no easy way to avoid this kind of error via static time analysis. 不幸的事实是,没有通过静态时间分析来避免此类错误的简便方法。 Consider this: 考虑一下:

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

The first line proves that possiblyUnsafeOp() returns a non-null and cannot be called an error in writing the test. 第一行证明,可能UnsafeOp()返回非null,并且在编写测试时不能称为错误。

You have no warnings because the assert tests the assignment, and it works. 您没有警告,因为断言可以测试分配,并且可以正常工作。 As blobonat said a safer code would be : -0.5 = variable 正如blobonat所说,更安全的代码是: -0.5 = variable

That pattern is useful for going through a list until 0 is found, so people might write that on purpose, this is why no warning is generated. 该模式对于在找到0之前的列表中很有用,因此人们可能会故意写出来,这就是为什么不生成警告的原因。 For example: 例如:

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

instead of: 代替:

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

Or to do something only if a function returned non-0 which usually means an error 或仅在函数返回非零(通常表示错误)时才执行某项操作

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

In your case variable was being assigned -0.5 and when that was casted to the int that an assert expects it was clamped to 0. You can avoid this by changing the positions of the check, because -0.5 = variable is not valid (but -0.5 == variable is), so it wouldn't compile unless you've putted the two = signs. 在您的情况下,变量被分配了-0.5,并且在将其强制转换为断言期望将其固定为0的int时。您可以通过更改检查的位置来避免这种情况,因为-0.5 = variable无效(但是-0.5 == variable ),因此除非您将两个=符号放在一起,否则它不会编译。

This behavior can come in handy actually, what if you want to evaluate some complex statement using assert but you have to do some assignments beforehand? 这种行为实际上可以派上用场,如果您想使用assert来评估一些复杂的语句,但必须事先进行一些分配,该怎么办? in this case (can't think of a valid example right now, but i do remember using it this way) you can do: 在这种情况下(现在想不出一个有效的示例,但我确实记得以此方式使用过),您可以执行以下操作:

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

This cannot be used in the release version obviously but can be helpful with complex asserts. 这显然不能在发行版本中使用,但对于复杂的断言可能会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM