I have stumbled upon an if statement where the condition is actually an assignment and I don't really understand what it does. Now, I found a similar Question with extensive answers but I still don't quite understand, what my snippet does:
if ((x = !x))
/* some code */
The similar question I found is this one: https://unix.stackexchange.com/questions/306111/what-is-the-difference-between-the-bash-operators-vs-vs-vs
One user states, that
((…)) double parentheses surround an arithmetic instruction, that is, a computation on integers, with a syntax resembling other programming languages. This syntax is mostly used for assignments and in conditionals. This only exists in ksh/bash/zsh, not in plain sh.
What does that mean? Is the value of x toggled now and nothing else happened? In what case does this condition return false?
It does the same thing as if(x = !x) does. However, because it is very easy to accidentally use = in place of ==, compilers will warn you when you're using an assignment inside of an if statement. That warning doesn't get displayed if the assignment expression is inside of a second set of parenthesis.
So that's the point of the extra parens: to tell the compiler/reader that the writer really meant to use assignment rather than equality testing.
Related
I'm hoping to perform the following steps in a single IF statement to save on code writing:
If ret is TRUE, set ret to the result of function lookup(). If ret is now FALSE, print error message.
The code I've written to do this is as follows:
BOOLEAN ret = TRUE;
// ... functions assigning to `ret`
if ( ret && !(ret = lookup()) )
{
fprintf(stderr, "Error in lookup()\n");
}
I've got a feeling that this isn't as simple as it looks. Reading from, assigning to and reading again from the same variable in an IF statement. As far as I'm aware, the compiler will always split statements like this up into their constituent operations according to precedence and evaluates conjuncts one at a time, failing immediately when evaluating an operand to false rather than evaluating them all. If so, then I expect the code to follow the steps I wrote above.
I've used assignments in IF statements a lot and I know they work, but not with another read beforehand.
Is there any reason why this isn't good code? Personally, I think it's easy to read and the meaning is clear, I'm just concerned about the compiler maybe not producing the equivalent logic for whatever reason. Perhaps compiler vendor disparities, optimisations or platform dependencies could be an issue, though I doubt this.
...to save on code writing This is almost never a valid argument. Don't do this. Particularly, don't obfuscate your code into a buggy, unreadable mess to "save typing". That is very bad programming.
I've got a feeling that this isn't as simple as it looks. Reading from, assigning to and reading again from the same variable in an IF statement.
Correct. It has little to do with the if statement in itself though, and everything to do with the operators involved.
As far as I'm aware, the compiler will always split statements like this up into their constituent operations according to precedence and evaluates conjuncts one at a time
Well, yes... but there is operator precedence and there is order of evaluation of subexpressions, they are different things. To make things even more complicated, there are sequence points.
If you don't know the difference between operator precedence and order of evaluation, or if you don't know what sequence points are, you need to instantly stop stuffing as many operators as you can into a single line, because in that case, you are going to write horrible bugs all over the place.
In your specific case, you get away with the bad programming just because as a special case, there happens to be a sequence point between the left and right evaluation of the && operator. Had you written some similar mess with a different operator, for example ret + !(ret = lookup(), your code would have undefined behavior. A bug which will take hours, days or weeks to find. Well, at least you saved 10 seconds of typing!
Also, in both C and C++ use the standard bool type and not some home-brewed version.
You need to correct your code into something more readable and safe:
bool ret = true;
if(ret)
{
ret = lookup();
}
if(!ret)
{
fprintf(stderr, "Error in lookup()\n");
}
Is there any reason why this isn't good code?
Yes, there are a lot issues whith such dirty code fragments!
1)
Nobody can read it and it is not maintainable. A lot of coding guidlines contain a rule which tells you: "One statement per line".
2) If you combine multiple expressions in one if statement, only the first statements will be executed until the expression is defined! This means: if you have multiple expressions which combined with AND the first expression which generates false will be the last one which will be executed. Same with OR combinations: The first one which evaluates to true is the last one which is executed.You already wrote this and you! know this, but this is a bit of tricky programming. If all your colleges write code that way, it is maybe ok, but as I know, my colleagues will not understand what you are doing in the first step!
3) You should never compare and assign in one statement. It is simply ugly!
4) if YOU! already think about " I'm just concerned about the compiler maybe not producing the equivalent logic" you should think again why you are not sure what you are doing! I believe that everybody who must work with such a dirty code will think again on such combinations.
Hint: Don't do that! Never!
This question already has answers here:
Uses of C comma operator [duplicate]
(20 answers)
Closed 9 years ago.
Good day, everyone.
I've come across a peculiar piece of code today, which I don't quite understand.
I don't even know how to search for this particular problem.
In this code, which works, a variable assignment is done like this:
if(condition) {
Var1 = false, Var2 = false;
}
Now, I was under the impression, that ALL commands need to be terminated by a semicolon instead of a comma. I am familiar with the syntax
Var1 = Var2 = false;
but not with the one posted above. The compiler (g++) doesn't even throw me a warning or anything...am I missing something from the specification here?
Or is the compiler generous with me and just replaces the , with a ; internally? If so, shouldn't he at least throw a warning?
Thank you for your time.
am I missing something from the specification here?
Yes, it's the "comma operator", specified by C++11 5.18. It evaluates the sub-expression to the left, then the one to the right, and the overall result is that of the right-hand one.
In this case, it's equivalent to two expression statements separated by ;
It's useful in places like if/while/for where you're only allowed one expression, but might want to do more than one thing:
while (++i, --j != 0)
and also if you like to jam multiple statements together to make life difficult for whoever has to read your code.
In the C and C++ programming languages, the comma operator (represented by the token ,) is a binary operator that evaluates its first operand and discards the result, and then evaluates the second operand and returns this value (and type). (read more)
As Alexandru Barbarosie pointed out, there's quite a thorough explanation on what's happening at https://stackoverflow.com/questions/1613230/uses-of-c-comma-operator
To quickly summarize it for whomever stumbles across this post: When used outside of for loops and stuff, the , actually has the same effect as the ;.
For more information, please visit the link.
This question already has answers here:
What is the difference between these (bCondition == NULL) and (NULL==bCondition)? [duplicate]
(6 answers)
Closed 9 years ago.
I have received code from someone working earlier on it, and it contains a lot of lines like
while(false==find && false == err && k<kmax)
if(true==refract(ep1,ep2,n1,RI_blood, RI_collagen))
and my favorite line is
if(false == (ret_s<0))
The other code is done really well, documented just fine, but these lines with these odd conditions are throwing me off, and I wonder why they are done that way.
Especially that false==(ret_s<0) is completely confusing, and you kind of need to read that line like three times to understand what they want there.
Is this a common programming style, don't I understand the reasoning for that, or is that just bad style?
Edit: I don't feel this is similar to if(object==NULL) vs if(NULL==object), since this isn't about accidental assigning but about obfuscated if clauses...
Is this a common programming style?
No.
don't I understand the reasoning for that?
Some people like to explicitly compare booleans with true or false, even though the result is exactly the same boolean value. The logic is presumably that, by making the code harder to read and more surprising, people will think harder about it and make fewer assumptions about its behaviour. Or perhaps just that code should be hard to maintain, since it was hard to write.
Others like to write comparisons with constants backwards, which prevents mistakes like if (x = 5) when you meant if (x == 5). Any modern compiler will warn you about this mistake, so again its only real purpose is to make the code harder to read.
Combining these two behaviours gives the bizarre code you posted.
Or is that just bad style?
It's a style. I'm no judge of style, but if you like to keep maintainence programmers on their toes, it certainly does that. Personally, I like my code to be readable, but that's just me.
my favorite line is
I once encountered return a && !b implemented in about ten lines of code. The first line was switch(a).
Yoda Conditions
Using if(constant == variable) instead of if(variable == constant), like if(4 == foo). Because it's like saying "if blue is the sky" or "if tall is the man".
Its a safe guard against assignment in C++.
In C++ it is perfectly legal to do this
if (foo = true) ....
In this case the single = is an assignment and would replace the value of foo.
This is not legal and will generate a compiler error
if (true = foo) ....
Constants and literals are often put on the left because it prevents accidental assignments. Consider typing:
if(foo == bar)
as:
if(foo = bar)
The second might appear to work... but silently clobber foo. If foo is a constant, this error is not longer possible.
It's a self-protection technique that prevents you from accidentally typing an assignment operator (=) instead of equality operator (==), which can introduce strange bugs. Putting the constant value on the left hand side will introduce a compiler error, while putting a variable on the LHS will just silently compile.
Perhaps the original programmer thought that explicit comparison to true or false was clearler than if(condition) or if(!condition) and coded things in that way. I haven't seen this particular style before however.
It's quite subjective but I find while(!find && !err && k<kmax) easier to read.
The code could have been written for a shop where there is a site standard that every conditional statement must include a comparison operator, in order to avoid accidentally leaving out part of the comparison. (Maybe that's a stretch, but you did say that the rest of the code was very good.) That, coupled with a standard or habit of putting the constant on the left to avoid accidentally using = instead of == would give pretty much the code you showed. It doesn't explain the use of 'false' instead of the more natural 'true', though. Maybe it's a (misguided on multiple levels) attempt to gain microefficiency by comparing to zero instead of 1 at the machine level.
for my is only bad style,
if(false == (ret_s<0))
is equals to in C#
if(!(ret_s<0))
What is the difference between (x == "x") and ("x" == x) comparison in C++? Let's say x is a std::string. Is there any reason why one would be preferred over the other?
One is a string literal "X", and the other is an instance of std::string. Some advocate having the constant "x" on the left hand side, because that way you would get a compiler error if you use assignment = instead of equality ==:
if ("x" = x) // Error! Trying to assign to const char[]
if (x = "x") // Setting the value of x to be "x", and evaluating "x".
// Probably not what you want.
Other than that, there's really no difference.
I think both calls will result in call to bool std::string operator==(const std::string&, const std::string&).
This is because there are no implicit conversion operators from std::string to const char*, but there is implicit constructor from const char* to std::string.
EDIT:
on g++ 4.4.5 both comparisons works.
Here says the now closed question on Yoda Conditionals:
This is one of the things that I hate
most when I see it in someone else's
code. I know what it means and why
some people do it this way ("what if I
accidentally put '=' instead?"). For
me it's very much like when a child
goes down the stairs counting the
steps out loud.
Anyway, here are my arguments against
it:
It disrupts the natural flow of reading the program code. We, humans,
say "if value is zero" and not "if
zero is value".
Modern compilers warn you when you have an assignment in your condition,
or actually if your condition consists
of just that assignment, which, yes,
looks suspicious anyway
You shouldn't forget to put double '=' when you are comparing values if
you are a programmer. You may as well
forget to put "!" when testing
non-equality.
-mojuba
Accepted answer:
Ah, yes, "Yoda conditionals" ("If zero
the value is, execute this code you
must!"). I always point anyone who
claims they're "better" at tools like
lint(1). This particular problem has
been solved since the late 70s. Most
modern languages won't even compile
this, as they refuse to coerce the
result of the assignment to a boolean.
As others have said, it certainly
isn't a problem, but it does provoke a
bit of cognitive dissonance.
-TMN
I prefer using for NSStrings...
([x isEqualToString:#"x"])
or for c strings
strcmp(str1,str2);
There is no difference between those two conditions, other than maybe something internal. It's like holding two things in your hands, one in each hand, and comparing them - and then basing then factoring in which hand each one is in. ...That's not something that's a factor.
I have read in a lot of places but I really can't understand the specified behavior in conditionals.
I understand that in assignments it evaluates the first operand, discards the result, then evaluates the second operand.
But for this code, what it supposed to do?
CPartFile* partfile = (CPartFile*)lParam;
ASSERT( partfile != NULL );
bool bDeleted = false;
if (partfile,bDeleted)
partfile->PerformFileCompleteEnd(wParam);
The partfile in the IF was an unnecessary argument, or it have any meaning?
In this case, it is an unnecessary expression, and can be deleted without changing the meaning of the code.
The comma operator performs the expression of the first item, discards the results, then evaluates the result as the last expression.
So partfile,bDeleted would evaulate whatever partfile would, discard that result, then evaluate and return bDeleted
It's useful if you need to evaluate something which has a side-effect (for example, calling a method). In this case, though, it's useless.
For more information, see Wikipedia: Comma operator
bool bDeleted = false;
if (partfile,bDeleted)
partfile->PerformFileCompleteEnd(wParam);
Here, the if statement evaluates partfile,bDeleted, but bDelete is always false, so the expression fails to run. The key question is "what's that all about?". The probable answer is that someone temporarily wanted to prevent the partfile->PerformFileCompleteEnd(wParam); statement from running, perhaps because it was causing some problem or they wanted to ensure later code reported errors properly if that step wasn't performed. So that they're remember how the code used to be, they left the old "if (partfile)" logic there, but added a hardcoded bDeleted variable to document that the partfile->Perform... logic had effectively been "deleted" from the program.
A better way to temporarily disable such code is probably...
#if 0
if (partfile)
partfile->PerformFileCompleteEnd(wParam);
#endif
...though sometimes I try to document the reasoning too...
#ifndef DONT_BYPASS_FILE_COMPLETE_PROCESSING_DURING_DEBUGGING
if (partfile)
partfile->PerformFileCompleteEnd(wParam);
#endif
...or...
if (partFile, !"FIXME remove this after debugging")
partfile->PerformFileCompleteEnd(wParam);
The best choice depends on your tool set and existing habits (e.g. some editors highlight "FIXME" and "TODO" in reverse video so it's hard to miss or grey out #if 0 blocks; you might have particular strings your source-control checkin warns about; preprocessor defines only in debug vs release builds can prevent accidental distribution etc.).
partfile is evaluated, then bDeleted is evaluated and used as the test. Since evaluation of partfile does not have any side effects, removing it from the conditional has no effect.
The comma operator is a rather obscure feature of C/C++. It should not be confused with the comma in initialising lists (ie: int x, int y; ) nor with function call parameter separation comma (ie: func(x, y) ).
The comma operator has one single purpose: to give the programmer a guaranteed order of evaluation of an expression. For almost every operator in C/C++, the order of evaluation of expressions is undefined. If I write
result = x + y;
where x and y are subexpressions, then either x or y can be evaluated first. I cannot know which, it's up to the compiler. If you however write
result = x, y;
the order of evaluation is guaranteed by the standard: left first.
Of course, the uses of this in real world applications are quite limited...