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

C++ 为什么我在写=而不是==时没有收到警告?,c++,visual-c++,visual-studio-2015,C++,Visual C++,Visual Studio 2015,由于这条无效的语句,在数小时内努力最终识别一个bug: ... assert( variable = -0.5 ); 这显然应该是assert(变量==-0.5):开发人员输入错误 我正在使用Visual Studio 2015进行编译,并真正致力于进行“0警告编译” 在编译器没有报告警告的情况下,如何编译这样一个糟糕而危险的语句?我们是否没有可以启用的编译器选项来避免这种情况 编辑:即使是bool b=(变量=-0.5)也不会产生任何编译器警告条件表达式中的赋值只有在使用编译级别时才会受到警

由于这条无效的语句,在数小时内努力最终识别一个bug:

...
assert( variable = -0.5 );
这显然应该是
assert(变量==-0.5):开发人员输入错误

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

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


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

条件表达式中的赋值只有在使用编译级别时才会受到警告,请参阅

因此,我使用在线MSVC编译器(我在这台电脑上没有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);
}


显然,在某些配置下,QT头
qglobal.h
使用
QT\u warning\u DISABLE\u MSVC(4706)
禁用此警告。

此行为实际上很方便,如果您想使用assert对某个复杂语句求值,但必须事先进行一些赋值,该怎么办?在这种情况下(我现在想不出一个有效的例子,但我记得用这种方法),你可以:

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

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

不幸的是,没有简单的方法可以通过静态时间分析避免此类错误。考虑这一点:

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

第一行证明possiblyUnsafeOp()返回一个非null值,在编写测试时不能被称为错误。

您没有任何警告,因为assert测试赋值,并且它可以工作。
正如blobonat所说,更安全的代码是:
-0.5=variable

您不会收到警告,因为这是一个完全合法且使用过的表达式,例如

while( (char c = getNextChar()) ) ...
因此,有些人在与常量进行比较时,倾向于将常量写在lhs上:

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

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

相比,这个模式对于在找到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,当它被强制转换为断言期望的int时,它被钳制为0。您可以通过更改检查的位置来避免这种情况,因为
-0.5=variable
无效(但
-0.5==variable
无效),因此除非您放置了两个=符号,否则它不会编译。

您使用的警告级别是什么?您使用的是编译器警告级别4吗?@NathanOliver:Default(/W3),/Wall也不会发出任何警告。是否启用了断言?如果禁用它们,预处理器会在编译器有机会发出警告之前完全清除
variable=-0.5
。另一个很好的例子是,使用Yoda条件可以节省(大量?)时间。:-)@Xarn:正如在OP中所评论的,即使使用/W4也没有警告(可能是VS..@jpo38中的一个bug),您是在调试中编译的吗?或者更确切地说,启用了断言?另一个选项是断言不够透明,编译器无法看到赋值在条件表达式中。@jpo38:我怀疑这是VS错误。如果您已将警告设置为“最大”,但仍然没有收到警告,则应查看“项目属性”>“C\C++>高级”>“禁用特定警告”,以查看是否有人禁用了该警告。@Xarn:正如对其他答案的评论,甚至
bool b=(refSlope=-0.5)不产生任何警告。因此,
assert
不是问题的根本原因。@jpo38您真的启用了
/W4
?在注释中,您仅指定
/W3
。因为我刚刚测试了这个,并(在一分钟内)看到了答案。断言不是问题的根本原因。偶数
bool b=(参考斜率=-0.5)不产生警告。是的,我谈论断言,因为它是在他的代码中使用的。断言中的矫揉造作是问题的根源。这是一个可怕的想法,因为断言是发布版本中的noop。为什么所有的否决?我没有说你应该在发行版中使用它,你可以用它来做复杂的断言,这有什么错?@monkeyStix就像其他两个被删除的答案一样,这忽略了问题的关键:如果编译器警告像
if(i=0)
,为什么他们不警告dodgier
断言(i=0)的方式
也是?@Baum mit Augen虽然我自己不喜欢,但对于一些在if和while中进行赋值的人来说,这是一种常见的做法,我只是解释了为什么默认行为是不警告用户。这是一个可怕的想法,因为断言在发布版本中是不存在的。是的,这是可怕的代码。然而,这只是为了说明有人可能会做些什么来阻止实际的警报系统捕捉到东西@阿尔克:嗯。。我一直不明白为什么我们不能保持
:=
甚至

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