C++ “if”条件下的变量赋值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17681535/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Variable assignment in "if" condition
提问by Smash
I recently just lost some time figuring out a bug in my code which was caused by a typo:
我最近只是浪费了一些时间来找出我的代码中由拼写错误引起的错误:
if(a=b)
instead of:
代替:
if(a==b)
I was wondering if there is any particular case you would want to assign a value to a variable in a if
statement, or if not, why doesn't the compiler throw a warning or an error ?
我想知道是否有任何特殊情况您想要在if
语句中为变量赋值,或者如果没有,为什么编译器不抛出警告或错误?
回答by Lightness Races in Orbit
if (Derived* derived = dynamic_cast<Derived*>(base)) {
// do stuff with `derived`
}
Though this is oft cited as an anti-pattern ("use virtual dispatch!"), sometimes the Derived
type has functionality that the Base
simply does not (and, consequently, distinct functions), and this is a good way to switch on that semantic difference.
尽管这经常被引用为反模式(“使用虚拟调度!”),但有时Derived
类型具有Base
根本没有的功能(因此,不同的功能),这是打开语义差异的好方法.
回答by cmaster - reinstate monica
Here is some history on the syntax in question.
这是有关语法的一些历史记录。
In classical C, error handling was frequently done by writing something like:
在经典 C 中,错误处理经常通过编写如下内容来完成:
int error;
...
if(error = foo()) {
printf("An error occured: %s\nBailing out.\n", strerror(error));
abort();
}
Or, whenever there was a function call that might return a null pointer, the idiom was used the other way round:
或者,每当有一个可能返回空指针的函数调用时,习惯用法就会反过来使用:
Bar* myBar;
... //in old C variables had to be declared at the start of the scope
if(myBar = getBar()) {
//do something with myBar
}
However, this syntax is dangerously close to
然而,这种语法危险地接近于
if(myValue == bar()) ...
which is why many people consider the assignment inside a condition bad style, and compilers started to warn about it (at least with -Wall
). However, this warning can be avoided by adding an extra set of parentheses:
这就是为什么许多人认为条件中的赋值风格不好,并且编译器开始警告它(至少使用-Wall
)。但是,可以通过添加一组额外的括号来避免此警告:
if((myBar = getBar())) { //tells the compiler: Yes, I really want to do that assignment!
Then C99 came around, allowing you to mix definitions and statements, so many developers would frequently write something like
然后 C99 出现了,允许您混合定义和语句,因此许多开发人员会经常编写类似
Bar* myBar = getBar();
if(myBar) {
which does feel awkward. This is why the newest standard allows definitions inside conditions, to provide a short, elegant way to do this:
这确实让人感到尴尬。这就是为什么最新标准允许在条件内定义,以提供一种简短、优雅的方式来做到这一点:
if(Bar* myBar = getBar()) {
There is no danger in this statement anymore, you explicitely give the variable a type, obviously wanting it to be initialized. It also avoids the extra line to define the variable, which is nice. But most importantly, the compiler can now easily catch this sort of bug:
这个语句不再有危险,你明确地给变量一个类型,显然希望它被初始化。它还避免了定义变量的额外行,这很好。但最重要的是,编译器现在可以轻松捕获此类错误:
if(Bar* myBar = getBar()) {
...
}
foo(myBar->baz); //compiler error
//or, for the C++ enthusiasts:
myBar->foo(); //compiler error
Without the variable definition inside the if
statement, this condition would not be detectable.
如果if
语句中没有变量定义,则无法检测到这种情况。
To make a long answer short: The syntax in you question is the product of old C's simplicity and power, but it is evil, so compilers can warn about it. Since it is also a very useful way to express a common problem, there is now a very concise, bug robust way to achieve the same behaviour. And there is a lot of good, possible uses for it.
简而言之:您问题中的语法是旧 C 的简单性和强大功能的产物,但它是邪恶的,因此编译器可以警告它。由于它也是表达常见问题的一种非常有用的方式,因此现在有一种非常简洁、具有错误鲁棒性的方式来实现相同的行为。它有很多好的、可能的用途。
回答by Maroun
The assignment operator returns the value of the assigned value. So, I might use it in situation like this:
赋值运算符返回赋值的值。所以,我可能会在这样的情况下使用它:
if (x = getMyNumber())
I assign x
to be the value returned by getMyNumber
and I check if it's not zero.
我指定x
为返回的值,getMyNumber
并检查它是否不为零。
Avoid doing that, I gave you an example just to help you understand this.
避免这样做,我举了一个例子来帮助你理解这一点。
Edit:adding Just a suggestion.
编辑:添加只是一个建议。
To avoidsuch bugs up-to some extends one should write if condition as if(NULL == ptr)
instead of if (ptr == NULL)
Because When you misspell the equality check operator ==
as operator =
, the compile will throw an lvalue error with if (NULL = ptr)
, but if (res = NULL)
passed by the compiler (which is not what you mean) and remain a bug in code for runtime.
为了避免这种错误,直到某些扩展,你应该写 if condition asif(NULL == ptr)
而不是if (ptr == NULL)
因为当你将相等检查运算符错误拼写==
为 operator 时=
,编译将抛出一个左值错误if (NULL = ptr)
,但if (res = NULL)
由编译器传递(这不是你的意思)并且仍然是运行时代码中的错误。
One should also read Criticismregarding this kind of code.
人们还应该阅读关于这种代码的批评。
回答by James Kanze
It depends on whether you want to write clean code or not. When C was first being developed, the importance of clean code wasn't fully recognized, and compilers were very simplistic: using nested assignment like this could often result in faster code. Today, I can't think of any case where a good programmer would do it. It just makes the code less readable and more difficult to maintain.
这取决于您是否想编写干净的代码。最初开发 C 时,并未完全认识到干净代码的重要性,而且编译器非常简单:使用这样的嵌套赋值通常可以生成更快的代码。今天,我想不出一个好的程序员会做的任何情况。它只会降低代码的可读性和维护难度。
回答by Adrian McCarthy
why doesn't the compiler throw a warning
为什么编译器不抛出警告
Some compilers willgenerate warnings for suspicious assignments in a conditional expression, though you usually have to enable the warning explicitly.
一些编译器会为条件表达式中的可疑赋值生成警告,尽管您通常必须显式启用警告。
For example, in Visual C++, you have to enable C4706(or level 4 warnings in general). I generally turn on as many warnings as I can and make the code more explicit in order to avoid false positives. For example, if I really wanted to do this:
例如,在 Visual C++ 中,您必须启用C4706(或一般的 4 级警告)。我通常会尽可能多地打开警告并使代码更加明确以避免误报。例如,如果我真的想这样做:
if (x = Foo()) { ... }
Then I'd write it as:
然后我会写成:
if ((x = Foo()) != 0) { ... }
The compiler sees the explicit test and assumes that the assignment was intentional, so you don't get a false positive warning here.
编译器看到显式测试并假定分配是有意的,因此您不会在此处收到误报警告。
The only drawback with this approach is that you can't use it when the variable is declared in the condition. That is, you cannot rewrite:
这种方法的唯一缺点是在条件中声明变量时不能使用它。也就是说,你不能重写:
if (int x = Foo()) { ... }
as
作为
if ((int x = Foo()) != 0) { ... }
Syntactically, that doesn't work. So you either have to disable the warning, or compromise on how tightly you scope x
.
从语法上讲,这是行不通的。因此,您要么必须禁用警告,要么对范围的紧密程度做出妥协x
。
UPDATE:C++17 added the ability to have an init-statement in the condition for an if-statement (p0305r1), which solves this problem nicely (for kind of comparison, not just != 0
).
更新:C++17 添加了在 if 语句 ( p0305r1)的条件中使用 init 语句的能力,这很好地解决了这个问题(用于比较,而不仅仅是!= 0
)。
if (x = Foo(); x != 0) { ... }
Furthermore, if you want, you can limit the scope of x
to just the if-statement:
此外,如果需要,您可以将范围限制x
为仅 if 语句:
if (int x = Foo(); x != 0) { /* x in scope */ ... }
// x out of scope
回答by elatalhm
I ran into a case where this was useful just recently so I thought I'd post it.
我最近遇到了一个很有用的案例,所以我想我会发布它。
Suppose you want to check several conditions in a single if, and if any one of the conditions is true, you'd like to generate an error message. If you want to include in your error message which specific condition caused the error, you could do the following:
假设您想在一个 if 中检查多个条件,并且如果其中任何一个条件为真,您希望生成一条错误消息。如果您想在错误消息中包含导致错误的特定条件,您可以执行以下操作:
std::string e;
if( myMap[e = "ab"].isNotValid() ||
myMap[e = "cd"].isNotValid() ||
myMap[e = "ef"].isNotValid() )
{
// here, e has the key for which the validation failed
}
So if the second condition is the one that evaluates to true, e will be equal to "cd". This is due to the short-circuit behaviour of ||
which is mandated by the standard (unless overloaded). See thisanswer for more details on short-circuiting.
因此,如果第二个条件的计算结果为真,则 e 将等于“cd”。这是由于||
标准规定的短路行为(除非过载)。有关短路的更多详细信息,请参阅此答案。
回答by tadman
Doing assignment in an if
is a fairly common thing, though it's also common that people do it by accident.
在 anif
中进行赋值是一件相当普遍的事情,尽管人们不小心这样做也很常见。
The usual pattern is:
通常的模式是:
if (int x = expensive_function_call())
{
// ...do things with x
}
The anti-pattern is where you're mistakenly assigning to things:
反模式是您错误地分配给事物的地方:
if (x = 1)
{
// Always true
}
else
{
// Never happens
}
You can avoid this to a degree by putting your constants or const
values first, so your compiler will throw an error:
您可以通过将常量或const
值放在首位来在一定程度上避免这种情况,因此您的编译器会抛出错误:
if (1 = x)
{
// Compiler error, can't assign to 1
}
=
vs. ==
is something you'll need to develop an eye for. I usually put whitespace around the operator so it's more obvious which operation is being performed, as longname=longername
looks a lot like longname==longername
at a glance, but =
and ==
on their own are obviously different.
=
vs.==
是你需要关注的东西。我通常在操作符周围放置空格,以便更清楚地longname=longername
看到正在执行的操作,longname==longername
一目了然,但=
和==
它们本身显然不同。