3

I am confused about the output of the code. It depends on what compiler i run the code. Why is it so?

#include <iostream>
using namespace std;
int f(int &n)
{   
    n--;
    return n;
}
int main()
{
      int n=10;
      n=n-f(n);
      cout<<n;
      return 0;
}

Running it on the Ubuntu terminal with g++, the output is 1 whereas running it on Turbo C++ ( the compiler we used in school) gives output as 0.

aman
  • 41
  • 5

1 Answers1

4

In C++03, modifying a variable and also using its value in the same expression, without an intervening C++03 sequence point, was Undefined Behavior.

C++03 §5/4:

Between the previous and next sequence point a scalar 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. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.

Undefined Behavior, UB, provides the compiler with an opportunity to optimize, because it can assume that UB does not occur in a valid program.

However, with all the myriad UB rules of C++ it's difficult to reason about source code.


In C++11 sequence points were replaced with sequenced before, indeterminately sequenced and unsequenced relations:

C++11 §1.9/3

Given any two evaluations A and B, if A is sequenced before B, then the execution of A shall precede the execution of B. If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [Note: The execution of unsequenced evaluations can overlap. —end note ] Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which.

And with the new C++11 sequence relationship rules the modification in the function in the code in question is indeterminately sequenced with respect to the use of the variable, and so the code has unspecified behavior rather than Undefined Behavior, as noted by Eric M Schmidt in a comment to (the first version of) this answer. Essentially that means that there is no danger of nasal daemons or other possible UB effects, and that the behavior is a reasonable one. The two possible behaviors here are that the modification via the function call is done before the use of the value, or that it's done after the use of the value.

Why it's unspecified behavior:

C++11 §1.9/15:

Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.

What “unspecified behavior” means:

C++11 §1.3.25:

unspecified behavior
Behavior, for a well-formed program construct and correct data, that depends on the implementation [Note: The implementation is not required to document which behavior occurs. The range of possible behaviors is usually delineated by this International Standard. —end note ]

Why the modification effected by the assignment is not problematic:

C++11 §5.17/1

In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.

This is also quite different from C++03.


As the rather drastic edit of this answer shows, following Eric's comment, this kind of issue is not simple! The main advice I can give is to as much as possible just Say No™ to effects governed by subtle or very complex rules, the corners of the language. Simple code has a better chance of being correct, while so called clever code does not have a good chance of being significantly faster.

Community
  • 1
  • 1
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • The given code does not have undefined behavior, merely unspecified behavior. – Eric M Schmidt Mar 19 '16 at 09:04
  • @EricMSchmidt: That's an interesting idea. In C++11 terms, are you saying that the function call does not have a "side effect on a scalar object" here, or are you saying that it's not unsequenced relative to the use of that object? – Cheers and hth. - Alf Mar 19 '16 at 09:08
  • It is not unsequenced, but rather indeterminately sequenced, because the decrement operation occurs in function f rather than main. "Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function." (1.9/15) – Eric M Schmidt Mar 19 '16 at 09:16
  • Oh. Thanks, I needed to fix this answer anyway, since it mixed C++03 and C++11 rules. I thought they were compatible but now it seems they're not. – Cheers and hth. - Alf Mar 19 '16 at 09:20
  • @EricMSchmidt: Better now? I think maybe I should discuss the sequencing of the assignment. Hm. – Cheers and hth. - Alf Mar 19 '16 at 09:38
  • 1
    Done. [[[[[[[[[[[[[[[[[[[[[[ – Cheers and hth. - Alf Mar 19 '16 at 09:48
  • I think you mix unspecified behavior and implementation-defined behavior. Both limit what can happen but first can change on whim but second should be defined by implementation and don't change. Great example is object moved from. If you like you could leave it with random valid value and it will be still conforming. – Yankes Mar 19 '16 at 13:22
  • @Yankes: I wrote that unspecified behavior must be documented but that's wrong. Sorry. :( Fixing. I guess I was tired here, I should have checked that. Not sure about what you say "can change on a whim". The consistency of the behavior, doesn't seem to be specified. – Cheers and hth. - Alf Mar 19 '16 at 18:10
  • @Cheersandhth.-Alf When I sad "on a whim" I mean that compiler can choose behavior on a case by case basis. Like order of function arguments evaluation. Some compilers change it based on optimization level. On [isocpp.org](https://groups.google.com/a/isocpp.org/forum/?fromgroups=#!topic/std-proposals/oQUOtYX4R3o) is discussion ablaut this. Some people want made this specified behavior other want leave it as is for future possible optimizations. – Yankes Mar 20 '16 at 14:15