简体   繁体   中英

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 ); : developer typo.

I'm compiling with Visual Studio 2015, and really work on having a "0-warning compilation".

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

Assignments within conditional expressions are only warned against if you are using /W4 compilation level, see see this .

So I tested it using an online MSVC compiler (I don't have VS 2015 on this PC) on this code:

//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:

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.

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:

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. = .

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.

You have no warnings because the assert tests the assignment, and it works. As blobonat said a safer code would be : -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. 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.

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? 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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