440,441 Members | 1,831 Online Need help? Post your question and get tips & solutions from a community of 440,441 IT Pros & Developers. It's quick & easy.

# Strange operands to conditional operator

 P: n/a Can anyone please tell me how the C language interprets the following code: #include int main(void) { int a = 1; int b = 10; int x = 3; int r; r = (x 0) ? a = b : 0; /* what does this statement mean */ printf("%d\n", r); return r; } The statement containing the conditional operator is the puzzle. If it was written as "r = (x 0) ? (a = b) : 0;" there wouldn't be a problem. However, according to the language standard, the conditional operator has higher precedence than an assignment operator, so the assignment of b to a should not be performed until after the conditional operator has been evaluated. So what value *should* be assigned to "r" - or is the code meaningless ? Thank you Paulo Nov 14 '06 #1
5 Replies

 P: n/a paulo wrote: Can anyone please tell me how the C language interprets the following code: #include int main(void) { int a = 1; int b = 10; int x = 3; int r; r = (x 0) ? a = b : 0; /* what does this statement mean */ printf("%d\n", r); return r; } The statement containing the conditional operator is the puzzle. If it was written as "r = (x 0) ? (a = b) : 0;" there wouldn't be a problem. However, according to the language standard, the conditional operator has higher precedence than an assignment operator, so the assignment of b to a should not be performed until after the conditional operator has been evaluated. So what value *should* be assigned to "r" - or is the code meaningless ? The order of precedence is not relevant to the question, IMHO (I'm prepared to be shown wrong, of course). The tertiary conditional operator (which I dislike, personally) must take the form "expr1?expr2:expr3". If expr2 contains an assignment, that's not going to wait until after the condtional has been evaluated - the conditional can't be evaluated until the the assignment takes place. So after the line in question, "a" contains 10, as does "r". Nov 14 '06 #2

 P: n/a "paulo" 0) ? (a=b) : 0); Now for the second part: order of evaluation. The order of evaluation of sub-expressions in a C expression is normally free. In the expression a+b, the implementation is free to fetch a first, b first, both in parallel, or however it chooses; as long as the addition is performed correctly, it does not matter. This can be a trap for the unwary: for example, in push(pop() - pop()), there is no guarantee which of the two pop()s is called first, and therefore no guarantee that the number which is pushed is the top of the stack minus the second stack member, or vice versa. Similarly, in func1() + func2()*func3(), the fact that * binds more closely than + does not mean that func2() and func3() must always be called before func1(). Nor, of course, the reverse. There is one thing, though, which is an exception to this freedom, and that is sequence points. There are certain spots in a C program at which every computation and side-effect must be finished, and the next set started. The obvious one is the end of a full expression, e.g. the end of a whole expression statement, or the controlling expression of an if statement; others are just before a function is called, after its arguments have been evaluated (but _not_ between two argument evaluations), just before a library function returns, and after the first operand of certain operators. That last one is significant, here. One of these operators is &&; there is a sequence point between the first and second operand of any && operation. This is useful, for example, when you do if (ptr && *ptr0). - If x>0, assign the value of b to both a and r. Note that there is no sequence point between the _second_ operand of ?: and its surrounding expression (here, the assignment to r), so the order in which b gets assigned to a and r is unspecified. - If x<0, don't touch either a or b, and assign 0 to r. Richard  FSVO "must". If the compiler can prove that the program cannot or will not detect the difference, it can shuffle as it likes. If it cannot prove this, however, it must adhere to the prescribed order.  Again, if it can be proved that you can't tell the difference - for example, if the compiler knows that this OS doesn't have memory protection, and reading from a null pointer doesn't do anything, it can ignore this rule. But _only_ if it makes no difference. Nov 14 '06 #3

 P: n/a paulo: r = (x 0) ? a = b : 0; /* what does this statement mean */ More verbosely, it can be written as: if (x 0) { a = b; r = a; } else { r = 0; } However, according to the language standard, the conditional operator has higher precedence than an assignment operator, so the assignment of b to a should not be performed until after the conditional operator has been evaluated. So what value *should* be assigned to "r" - or is the code meaningless ? Recently enough, someone posted a link to a post by Chris Torek (I believe, and apologies if I misspelled the name) which was very helpful in explaining operator evaluation and so forth. -- Frederick Gotham Nov 14 '06 #4

 P: n/a On Tue, 14 Nov 2006, Richard Bos wrote: "paulo" >Can anyone please tell me how the C language interprets the followingcode: > r = (x 0) ? a = b : 0; /* what does this statement mean */ [big snip] In toto, the statement r = (x 0) ? a = b : 0; means this: - Evaluate (x>0). - If x>0, assign the value of b to both a and r. Note that there is no sequence point between the _second_ operand of ?: and its surrounding expression (here, the assignment to r), so the order in which b gets assigned to a and r is unspecified. I snipped most of an excellent explanation! However, you might have gone a little overboard right here. At least, IMHO, you ought to have added that it's not the value of 'b' that gets assigned to 'r' --- it's the value of 'a', or possibly "the value of 'b', converted to a value of the same type as 'a'". If b,a,r are all of the same type, it doesn't really matter (AFAICT), but if the types are respectively int, unsigned char, int, then it could matter. - If x<0, don't touch either a or b, and assign 0 to r. -Arthur Nov 14 '06 #5

 P: n/a "paulo" int main(void) { int a = 1; int b = 10; int x = 3; int r; r = (x 0) ? a = b : 0; /* what does this statement mean */ printf("%d\n", r); return r; } [...] Others have explained how the language rules apply to this code. I'll make another point: this is bad code. As a puzzle, there's nothing wrong with it, but I'd never write something like that in production code. "a", "b", "x" and "r" are, in most contexts, lousy variable names. (But "x" could be acceptable as a parameter name for a mathematical function, and "r" might mean "radius" if it's sufficiently clear from context.) Embedding assignments within larger expressions is perfectly legal, but can lead to confusion. The associations of operands with operators is not ambiguous, but there's no good reason not to add parentheses to make it clearer, so a reader doesn't have to consult the language grammar to understand the code. (The compiler effectively does so, but that's its job.) r = ((x 0) ? (a = b) : 0); But I wouldn't use the "?:" operator at all here: if (x 0) { r = a = b; /* chained assignments are clear enough, IMHO */ } else { r = 0; } And as long as we're simplifying things, the whole program reduces to: #include int main(void) { puts("10"); return 10; } Finally, returning 10 from main() could have unpredictable results; the only portable return values are 0, EXIT_SUCCESS, and EXIT_FAILURE. Again, there's nothing wrong with the original code *as a puzzle*, and there's nothing wrong with puzzles. Solving such puzzles is one of the many things a good C programmer needs to know how to do (since we all occasionally need to understand code written by someone who thought he was "clever".) But another important skill is knowing not to write such code in the first place. -- Keith Thompson (The_Other_Keith) ks***@mib.org San Diego Supercomputer Center <* We must do something. This is something. Therefore, we must do this. Nov 14 '06 #6

### This discussion thread is closed

Replies have been disabled for this discussion. 