1

Why does the below program gives me the opposite answer after comparison operations are done?

main()
{
    int k=35;
    printf("%d\n%d\n%d",k==35,k=50,k<40); 
}

output

0 50 1

Harsh Sengar
  • 95
  • 1
  • 9
  • 3
    What results do you get and what did you expect? – simonc May 26 '13 at 07:46
  • 3
    Maybe you mean `k==35,k==50,k<40` – johnchen902 May 26 '13 at 07:46
  • 6
    The `k=50` mistake moves the code into undefined territory, since `k` is being modified and read without an intervening sequence point. –  May 26 '13 at 07:47
  • I have rolled back the change to the title to the original one. Since the OP is not participating in any discussion, we can't know what his real question had been. So leave it as it stands. – Jens Gustedt May 26 '13 at 08:48
  • 2
    "Unspecified", not undefined. Very different things. – Lee Daniel Crocker May 26 '13 at 08:48
  • 2
    @LeeDanielCrocker can you provide a citation for that? The sequence point rules were very unforgiving in the standard drafts I've read (haven't got around to C11 yet). I don't think you can rely on this `printf` statement not blowing up the universe. To simplify it a little: it's not just `i=i++` that's undefined, but `i==i++` too –  May 26 '13 at 08:57
  • One of the two needs to be changed, otherwise the question is meaningless. I think it's perfectly clear that the poster expected a particular order of the parameters being executed, but was seeing unexpected values being printed. Since he thought he understood what should be true and what should be false, and the values didn't line up with that, he thought he didn't understand when 0 was true or false and when non-zero was true or false. – xaxxon May 26 '13 at 09:04
  • 6.5.2.2.10 "The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is UNSPECIFIED, but there is a sequence point before the actual call." – Lee Daniel Crocker May 26 '13 at 09:10
  • 2
    @LeeDanielCrocker but there is no sequence point between the evaluation of the first argument and the evaluation of the second argument. The evaluation of the first argument reads `k`, and the evaluation of the second argument modifies `k`, and the value computed in the first argument is not used to determine the value stored into `k` in the second argument, so there must be a sequence point between them (see interjay's citation). –  May 26 '13 at 09:15
  • When I said "first argument" and "second argument", I forgot to count the format string as an argument. Hope that didn't cause any confusion –  May 26 '13 at 09:25
  • ISO/IEC 9899:2011 §6.5 **Expressions**: _¶2 If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings._ and references footnote 84: _This paragraph renders undefined statement expressions such as `i = ++i + 1;` `a[i++] = i;` while allowing `i = i + 1;` `a[i] = i;`_ – Jonathan Leffler May 26 '13 at 12:36

4 Answers4

9

This program is not a valid C program as per the C standard.
There are 2 problems associated with this program.

Problem 1: Unspecified Behavior

The order of evaluation of arguments to a function is Unspecified[Ref 1].

  • It could be left to right or
  • It could be right to left or
  • Any other magical order

Problem 2: Undefined Behavior

This has undefined behavior[Ref 2] because a variable should not be modified more than once without a intervening sequence point. Note that , in the function arguments does not introduce a sequence point. Thus k gets modified without a intervening sequence point and causes Undefined Behavior.

So you cannot rely on the behavior to be anything specific in this case. The program is not a valid C program.


[Ref 1]
C99 Standard 6.5.2.2.10:

The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.

[Ref 2]
C99 Standard 6.5.2:

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored.


Note that Unspecified and Undefined Behavior are terms defined by the standard as:

C99 Standard 3.19 Unspecified Behavior:

behavior where this International Standard provides two or more possibilities and imposes no requirements on which is chosen in any instance

C99 Standard 3.18 Undefined Behavior:

behavior, upon use of a nonportable or erroneous program construct, of erroneous data, or of indeterminately valued objects, for which this International Standard imposes no requirements

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 1
    You very definitely *can* rely on one of the above happening, though. The program will print "0 50 0", or "0 50 1", or "1 50 0" or "1 50 1", we just don't know which. If the compiler does anything else, it's broken. – Lee Daniel Crocker May 26 '13 at 08:47
  • 1
    @LeeDanielCrocker It can print different results on different invocations. It can even transfer money from the user's bank account to mine when there's a full moon :) – pmg May 26 '13 at 08:54
  • 1
    Sure, it can print different results on different invocations if the compiler is silly enough to code it that way, but it absolutely *cannot* do anything other than one of the four things outlined. This is not a nasal demon situation: the compiler abolutely *must* do the assignment before the function call, and evaluate the two boolean expressions before the function call, but those three might be in any order. If the program fails to to that, the compiler is broken. – Lee Daniel Crocker May 26 '13 at 09:00
  • interjay, below, argues that it might be both. I don't think the spec is that clear, but he might be right. I certainly can't imagine any real compiler doing anything weird. "gcc -std=c99 -pedantic" doesn't complain, but of course that doesn't prove anything. – Lee Daniel Crocker May 26 '13 at 10:54
4

Did you notice that the second argument to printf is k=50? This is an undefined behavior because the order of evaluation of the parameters is unspecified

UmNyobe
  • 22,539
  • 9
  • 61
  • 90
  • 1
    This is not "undefined behavior". This is simply unspecified order of operations. The comparisons will definitely evaluate to true or false: no nasal demons here. – Lee Daniel Crocker May 26 '13 at 07:52
  • agreed with unspecified order of operation but it seems to be the case of undefined behavior in `k=50`. as removing that part and trying out with other combinations like `printf("%d\n%d\n%d",k==35, k>55,k>40);` does give the convincing output – exexzian May 26 '13 at 07:56
  • @LeeDanielCrocker The behavior is not defined across all implementations of compilers for the language. It doesn't even have to compile to the same thing in the same compiler, technically. You can't reason about the situation, so there is no reason to try to answer further questions. – xaxxon May 26 '13 at 08:24
  • 1
    "Undefined behavior" has a very specific meaning. It's what you get when you access an array beyond its bounds, or access freed memory, etc. The program might produce a result, or crash, or email your boss, or make demons fly out of your nose. This is a very different situation. This program will very definitely print "0 50 0" or "0 50 1" or "1 50 0", or "1 50 1", we just don't know which. If a compiler does anything else, it's broken. – Lee Daniel Crocker May 26 '13 at 08:41
  • 3
    @LeeDanielCrocker: This *is* undefined behavior, because the value of `k` is modified and read without an intervening sequence point. There is no guarantee that the code will only print one of the options you provided. – interjay May 26 '13 at 08:46
  • The point between when all the arguments to a function are evaluated, and when the function is called, IS a sequence point. See section 6.5.2.2 of the spec. The assignment WILL take place before the function call, no question, and the other two expressions have no side effects. – Lee Daniel Crocker May 26 '13 at 08:55
  • 2
    @LeeDanielCrocker: From 6.5p2: "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. **Furthermore, the prior value shall be read only to determine the value to be stored.**" (emphasis mine) – interjay May 26 '13 at 09:02
  • that's subsection 1025 here, I believe: http://c0x.coding-guidelines.com/6.5.2.2.html – xaxxon May 26 '13 at 09:03
  • Yes, that means the the compiler is free to read the value once, and use that value for the boolean expressions without re-reading it, and may do the assignment either before or after that happens. Or it may re-read them, that's it's choice. It is NOT free to crash, or to call the function before the assignment, or to skip the assignment. – Lee Daniel Crocker May 26 '13 at 09:05
  • 2
    @LeeDanielCrocker 6.5 (2) in N1570 starts "If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined." The side effect of assigning 50 to `k` seems to be unsequenced relative to the value computations using `k` in the comparisons. (Paragraph 3: " Except as specified later, side effects and value computations of subexpressions are unsequenced.", I didn't find any indication that evaluation of different arguments is indeterminately sequenced.) – Daniel Fischer May 26 '13 at 10:15
  • @interjay and xaxxon thanks for the refs – UmNyobe May 27 '13 at 07:47
4

The order of evaluation of function arguments is not defined by the C standard. See C99 §6.5.2.2p10:

The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.

This means that each of the comparison k==35, the assignment k=50, and the test k<40 can happen in any order. When I tried your program using MSVC, the assignment happened first. Other compilers, or even other invocations of the same compiler, may choose different orders.

simonc
  • 41,632
  • 12
  • 85
  • 103
  • This is the correct answer until the poster updates the question, but if he updates the question, he won't have a question anymore. – xaxxon May 26 '13 at 08:23
  • 1
    This answer is inadequate because it fails to state the behavior is not defined at all by the C standard because k is accessed and modified separately between sequence points, per clause 6.5 paragraph 2 of both the C 1999 and 2011 standards. It is not merely argument evaluation order that is unspecified; the entire behavior is undefined. – Eric Postpischil May 26 '13 at 11:47
2

I wish you'd shown your output. However, my suspicion is that the problem is that you've included an assignment as one of the arguments to printf(), and heavens knows what order the three arguments were evaluated, i.e. k might have been 50 when the k==35 was evaluated ;-)

Arlie Stephens
  • 1,146
  • 6
  • 20