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

The output of the above program is "0 50 0" without quotes. My question is how k==35 and k > 40 are false? From my perspective, k is assigned 35 so "k==35" should be true; then k is assigned 50 in "k=50", so "k > 40" has to be true, doesn't it?

Jonathan Leffler
  • 666,971
  • 126
  • 813
  • 1,185
sam
  • 226
  • 3
  • 6
  • 17
  • Prove "then" part to us – Val Apr 26 '14 at 16:39
  • @pmg: It is **Undefined Behavior**, not simply unspecified order of executions. – Deduplicator Apr 26 '14 at 17:01
  • 1
    @pmg: `printf("%d %d\n", 42 + 1, 42 - 1);` is fully defined behaviour. You can't tell whether 43 is calculated before or after 41, but it doesn't matter because neither computation affects the other. The UB is modifying a variable that is used elsewhere in the overall expression (the `printf()` statement). Using `++k` or `k--` or any assignment to `k` as well as referencing `k` elsewhere is problematic. Note that `printf("%d %d\n", 42 + 1, k -= 3);` is defined behaviour; the value of `k` is only used once. – Jonathan Leffler Apr 26 '14 at 17:13

3 Answers3

4

The printf call invokes undefined behaviour.

The order of evaluation of arguments to a function is unspecified behaviour. It means that the arguments can be evaluated in any order from a set of all possible orders. The standard does not require the implementation to enforce any order. Also, the comma which separates the arguments is not the comma operator. This means there is no sequence point between the evaluation of the arguments. The only requirement is that all the arguments must be fully evaluated and all side effects must have taken place before the function is called. Now, the C99 standard §6.5 ¶2 says

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.

The evaluation of the arguments to a function is unsequenced. The assignment expression k = 50 evaluates to 50 but its side effect is to assign 50 to k. If this expression is evaluated first and its side effect immediately takes place, then the expression k == 35 would evaluate to true and k > 40 would evaluate to false. Thus depending on when the side effect of expression the k = 50 takes place, the other two expressions would evaluate to true or false. However, the other two expressions violate the second point in the above quoted part from the standard. The expressions access k but it is not to change the value of k. This violates the prior value shall be read only to determine the value to be stored clause. This is the reason for the undefined behaviour.

Just to emphasize, the undefined behaviour in your code is not because the order of evaluation of arguments is unspecified (not undefined, which is different), but it's because there's no sequence point between the evaluation of the arguments, and as a result, the above quoted part from the standard is violated in this context.

Undefined behaviour means the behaviour of the code is unpredictable. Anything can happen from program crash to your hard drive getting formatted to demons flying out your nose (to launch into hyperbole). This is only to emphasize that the standard does not require the implementation to deal with such cases and you should always avoid such code.

Furhter reading -

Community
  • 1
  • 1
ajay
  • 8,550
  • 7
  • 34
  • 67
  • can you please explain how to specify order? – sam Apr 26 '14 at 16:46
  • 1
    @sam You cannot specify the order of evaluation of the function arguments. The implementation is not even required to always evaluate them in the same order. It can evaluate them in any order from a group of possible orders. That's why it is called unspecified behaviour. You should not write code which depends on this order. – ajay Apr 26 '14 at 16:49
  • @Deduplicator order of evaluation of arguments is **unspecified** but the `printf` call invokes undefined behaviour because the standard says `Between the previous and next sequence point , the prior value of a scalar object that is modified by the evaluation of the expression, shall be accessed only to determine the value to be stored`. – ajay Apr 26 '14 at 17:02
  • "It means that the arguments can be evaluated in any order from a set of all possible orders." That would be dandy, because then there would be an ordering constraint, and thus no UB. Also, are you contradicting yourself or is there a difference between ordering and sequencing? – Deduplicator Apr 26 '14 at 17:15
  • @ajay got the concept..appreciated.. – sam Apr 26 '14 at 17:17
  • @Deduplicator The UB is not because of that. It's because of the quoted part of the standard. The variable `k` is accessed not to determine it's new value. – ajay Apr 26 '14 at 17:17
  • @ajay: But the part i quoted from your post implies that there is **some** ordering between the reads and the write. I know it is UB. – Deduplicator Apr 26 '14 at 17:22
  • @Deduplicator Even if the order of evaluation of arguments is fixed, it would still be UB. That's because there is no sequence point between the evaluation of arguments. Evaluation of one argument has side effect. It's not guaranteed when it will take place. At the same time, other two argument expressions access the value which will be modified due to the side effect. It's because of this that there's UB. – ajay Apr 26 '14 at 17:27
2

Your code invokes undefined behaviour because of the assignment in the argument list:

k = 50

You presumably want:

printf("%d %d %d\n", k == 35, k == 50, k > 40);

Since you embed an assignment in the argument list, any result is permissible. There is no required order of evaluation for arguments; they could be evaluated in any order — any result is correct. For your own sanity, do not ever write code that depends on the order of evaluation of arguments.

If the book you are learning from is not simply emphasizing that the order of evaluation is undefined and that any undefined behaviour is bad, then you should probably discard the book.

Jonathan Leffler
  • 666,971
  • 126
  • 813
  • 1,185
  • 3
    Actually, OP intended to do the assignment. – nneonneo Apr 26 '14 at 16:39
  • 1
    I think the question morphed while I was typing... – Jonathan Leffler Apr 26 '14 at 16:40
  • assignment `k=50` was intentional. actually i am new to c and this problem is from "let us c" book. It asks the output of this program and i am not getting how `k==35` and `k>40` are false if program is executed sequently? – sam Apr 26 '14 at 16:43
  • OK: it was deliberate. If the book is discussing undefined behaviour, it had better be explaining that the output is indeterminate — and discouraging you from writing such code. If it is not all about how bad the possibility of undefined behaviour is, then the whole section of the book should be discarded, and I'd worry about the rest of the book. – Jonathan Leffler Apr 26 '14 at 16:45
  • @JonathanLeffler: The output being indeterminate is not strong enough: Better stay with **UB**, as you did in your answer. Still, it should be emphasised. – Deduplicator Apr 26 '14 at 16:50
  • 1
    The book is [Let Us C](http://www.amazon.com/Let-Us-C-Computer-Science/dp/1934015253) and is in its 8th Edition. A number of reviews are very complimentary; one is not, and I suspect there is good reason behind the negative review. – Jonathan Leffler Apr 26 '14 at 16:56
1

It is Undefined Behavior, which means anything may happen.

Why is it UB?

The answer is simply that there is no ordering constraint, not even indeterminate sequencing, between a write of k and a read of k which is not used to determine the new value of k.

printf ( "\n%d %d %d", k == 35, k = 50, k > 40 );
// No ordering constraint between function arguments.

Aside: If the write happened in a function called in the argument list instead (not in the arguments to that function), it would be indeterminately sequenced and thus not UB.
Indeterminately sequenced means it is sequenced before or after without determining which. It is not quite as bad as UB (anything goes), but it should still not be relied on, as the order is unreliable.

int SetVar(int *p, int v) {return *p = v;}

printf ( "\n%d %d %d", k == 35, SetVar(&k, 50), k > 40 );
// No ordering constraint between function arguments, but
// the function call is indeterminately ordered
Community
  • 1
  • 1
Deduplicator
  • 41,806
  • 6
  • 61
  • 104
  • Can you elaborate on your aside? The term 'indeterminately sequenced' is defined in ISO/IEC 9899:2011 at §5.1.2.3 Program execution, in ¶3, but it is fairly intense for a beginner (heck; it intimidates me). – Jonathan Leffler Apr 26 '14 at 17:02
  • Indeterminately sequenced means it is either sequenced before or after, and it is not specified which, but it is sequenced. – Deduplicator Apr 26 '14 at 17:06
  • OK; but are you thinking of `printf("%d %d %d\n", k == 35, abs(k = 50), k > 40);`, or something more dramatic (`printf("%d %d %d\n", k == 35, modifier(&k), k > 40);` where the `modifier` function is passed a pointer? – Jonathan Leffler Apr 26 '14 at 17:09
  • The latter, the other does not add any constraints between printf arguments 1, 2, 4 and abs argument. Which is why I said in the function called. Should I add more emphasis? – Deduplicator Apr 26 '14 at 17:11
  • Not emphasis; example. Well, it is up to you, but I think example would clarify better than more explanation. – Jonathan Leffler Apr 26 '14 at 17:15
  • @JonathanLeffler: Added example – Deduplicator Apr 26 '14 at 17:21