sorry if my question is duplicate or not worth answering.
I have been the following code that produces the result that I am not understanding how.
int x=5;
int y;
y = ++x * ++x;
cout<<x <<endl;
cout<<y;
According to my little understanding of programming, the value of y should be 42, but, the output on the computer is 49. Kindly help what will be the output of variable y.
I am executing the code in Dev-C++.
Thanks in advance.
The short answer is that you have an undefined behavior in there.
The exact answer depends on which standard you use.
Pre C++11, we had the notion of sequence points. Intuitively, they are points in which all the values have been properly stored, such as at the end of statement (at the semicolon). The standard says that
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.
, which means that between 2 sequence points (for the sake of simplicity, read as between 2 semicolons), the value of a variable cannot be changed more than once. You change the value twice, using the increment operator.
C++11 removed the notion of sequence points with relationships of sequenced before, sequenced after or unsequenced, referring to the order in which the expressions are evaluated.
In arithmetic expressions,
If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or [...] the behaviour is undefined.
and there is no sequencing between the operators of an arithmetic expression. Therefore, it is still a case of undefined behavior, just for another reason.
This means in practice that the compiler can choose what to do, and, in your case, it produces the results you observe. You should try to avoid undefined behaviour in your programs as much as possible. Below are some references that expand on the subject:
https://en.cppreference.com/w/cpp/language/eval_order
Undefined behavior and sequence points
result= function_1()*function_2();
I am writing a code like above. What I want to know is while doing the multiplication, which function is called first? That is because, the first called function can effect the result returned from the other function. I assumed function_1() is called first, and when I tried I saw that it is really so. However, is it always the case? Does it depend on which compiler I use or the system I work on?
Order of evaluation is unspecified by the C++ (or the C) standard (see answer from Vlad). If your function_1 or function_2 have significant side-effects, it may become some unspecified behavior which you should absolutely avoid (like you should avoid undefined behavior). And in some cases (inlined functions with strong optimizations) the computations might be intermixed.
Think about weird cases like
static int i;
int function_1(void) { i++; return i; }
int function_2(void) { i+=2; return 3*i+1; }
It probably is implementation specific, and might depend upon the actual compiler and the optimization flags.
You should code as if the order of function calls is completely random and not reproducible (even if in practice it might be reproducible). Likewise, you should not expect any particular order of arguments evaluation (e.g. in f(i++, ++j) you don't know if i or j has been incremented first), even if for a given compiler that order might be fixed. Again, you should imagine a completely random and non-reproducible order.
As commented by David Schwartz, if you care about the order, you should code explicitly some sequence points
At last, if your code is depending upon some order, it is completely unreadable and for that simple readability reason you should avoid coding this way.
According to the C++ Standard (1.9 Program execution)
15 Except where noted, evaluations of operands of individual operators
and of subexpressions of individual expressions are unsequenced.
So in this expression
result= function_1()*function_2();
some compilers can evaluate at first function_1() and then function_2() while other compilers can evaluate at first function_2() and only then function_1(). Even if you write like
result= (function_1())*(function_2());
or
result= (function_1())*function_2();
or
result= function_1()*(function_2());
nothing will be changed relative to the order of evaluation of the operands.
I was reading about order of evaluation violations, and they give an example that puzzles me.
1) If a side effect on a scalar object is un-sequenced relative to another side effect on the same scalar object, the behavior is undefined.
// snip
f(i = -1, i = -1); // undefined behavior
In this context, i is a scalar object, which apparently means
Arithmetic types (3.9.1), enumeration types, pointer types, pointer to member types (3.9.2), std::nullptr_t, and cv-qualified versions of these types (3.9.3) are collectively called scalar types.
I don’t see how the statement is ambiguous in that case. It seems to me that regardless of if the first or second argument is evaluated first, i ends up as -1, and both arguments are also -1.
Can someone please clarify?
UPDATE
I really appreciate all the discussion. So far, I like #harmic’s answer a lot since it exposes the pitfalls and intricacies of defining this statement in spite of how straight forward it looks at first glance. #acheong87 points out some issues that come up when using references, but I think that's orthogonal to the unsequenced side effects aspect of this question.
SUMMARY
Since this question got a ton of attention, I will summarize the main points/answers. First, allow me a small digression to point out that "why" can have closely related yet subtly different meanings, namely "for what cause", "for what reason", and "for what purpose". I will group the answers by which of those meanings of "why" they addressed.
for what cause
The main answer here comes from Paul Draper, with Martin J contributing a similar but not as extensive answer. Paul Draper's answer boils down to
It is undefined behavior because it is not defined what the behavior is.
The answer is overall very good in terms of explaining what the C++ standard says. It also addresses some related cases of UB such as f(++i, ++i); and f(i=1, i=-1);. In the first of the related cases, it's not clear if the first argument should be i+1 and the second i+2 or vice versa; in the second, it's not clear if i should be 1 or -1 after the function call. Both of these cases are UB because they fall under the following rule:
If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined.
Therefore, f(i=-1, i=-1) is also UB since it falls under the same rule, despite that the intention of the programmer is (IMHO) obvious and unambiguous.
Paul Draper also makes it explicit in his conclusion that
Could it have been defined behavior? Yes. Was it defined? No.
which brings us to the question of "for what reason/purpose was f(i=-1, i=-1) left as undefined behavior?"
for what reason / purpose
Although there are some oversights (maybe careless) in the C++ standard, many omissions are well-reasoned and serve a specific purpose. Although I am aware that the purpose is often either "make the compiler-writer's job easier", or "faster code", I was mainly interested to know if there is a good reason leave f(i=-1, i=-1) as UB.
harmic and supercat provide the main answers that provide a reason for the UB. Harmic points out that an optimizing compiler that might break up the ostensibly atomic assignment operations into multiple machine instructions, and that it might further interleave those instructions for optimal speed. This could lead to some very surprising results: i ends up as -2 in his scenario! Thus, harmic demonstrates how assigning the same value to a variable more than once can have ill effects if the operations are unsequenced.
supercat provides a related exposition of the pitfalls of trying to get f(i=-1, i=-1) to do what it looks like it ought to do. He points out that on some architectures, there are hard restrictions against multiple simultaneous writes to the same memory address. A compiler could have a hard time catching this if we were dealing with something less trivial than f(i=-1, i=-1).
davidf also provides an example of interleaving instructions very similar to harmic's.
Although each of harmic's, supercat's and davidf' examples are somewhat contrived, taken together they still serve to provide a tangible reason why f(i=-1, i=-1) should be undefined behavior.
I accepted harmic's answer because it did the best job of addressing all meanings of why, even though Paul Draper's answer addressed the "for what cause" portion better.
other answers
JohnB points out that if we consider overloaded assignment operators (instead of just plain scalars), then we can run into trouble as well.
Since the operations are unsequenced, there is nothing to say that the instructions performing the assignment cannot be interleaved. It might be optimal to do so, depending on CPU architecture. The referenced page states this:
If A is not sequenced before B and B is not sequenced before A, then
two possibilities exist:
evaluations of A and B are unsequenced: they may be performed in any order and may overlap (within a single thread of execution, the
compiler may interleave the CPU instructions that comprise A and B)
evaluations of A and B are indeterminately-sequenced: they may be performed in any order but may not overlap: either A will be complete
before B, or B will be complete before A. The order may be the
opposite the next time the same expression is evaluated.
That by itself doesn't seem like it would cause a problem - assuming that the operation being performed is storing the value -1 into a memory location. But there is also nothing to say that the compiler cannot optimize that into a separate set of instructions that has the same effect, but which could fail if the operation was interleaved with another operation on the same memory location.
For example, imagine that it was more efficient to zero the memory, then decrement it, compared with loading the value -1 in. Then this:
f(i=-1, i=-1)
might become:
clear i
clear i
decr i
decr i
Now i is -2.
It is probably a bogus example, but it is possible.
First, "scalar object" means a type like a int, float, or a pointer (see What is a scalar Object in C++?).
Second, it may seem more obvious that
f(++i, ++i);
would have undefined behavior. But
f(i = -1, i = -1);
is less obvious.
A slightly different example:
int i;
f(i = 1, i = -1);
std::cout << i << "\n";
What assignment happened "last", i = 1, or i = -1? It's not defined in the standard. Really, that means i could be 5 (see harmic's answer for a completely plausible explanation for how this chould be the case). Or you program could segfault. Or reformat your hard drive.
But now you ask: "What about my example? I used the same value (-1) for both assignments. What could possibly be unclear about that?"
You are correct...except in the way the C++ standards committee described this.
If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined.
They could have made a special exception for your special case, but they didn't. (And why should they? What use would that ever possibly have?) So, i could still be 5. Or your hard drive could be empty. Thus the answer to your question is:
It is undefined behavior because it is not defined what the behavior is.
(This deserves emphasis because many programmers think "undefined" means "random", or "unpredictable". It doesn't; it means not defined by the standard. The behavior could be 100% consistent, and still be undefined.)
Could it have been defined behavior? Yes. Was it defined? No. Hence, it is "undefined".
That said, "undefined" doesn't mean that a compiler will format your hard drive...it means that it could and it would still be a standards-compliant compiler. Realistically, I'm sure g++, Clang, and MSVC will all do what you expected. They just wouldn't "have to".
A different question might be Why did the C++ standards committee choose to make this side-effect unsequenced?. That answer will involve history and opinions of the committee. Or What is good about having this side-effect unsequenced in C++?, which permits any justification, whether or not it was the actual reasoning of the standards committee. You could ask those questions here, or at programmers.stackexchange.com.
A practical reason to not make an exception from the rules just because the two values are the same:
// config.h
#define VALUEA 1
// defaults.h
#define VALUEB 1
// prog.cpp
f(i = VALUEA, i = VALUEB);
Consider the case this was allowed.
Now, some months later, the need arises to change
#define VALUEB 2
Seemingly harmless, isn't it? And yet suddenly prog.cpp wouldn't compile anymore.
Yet, we feel that compilation should not depend on the value of a literal.
Bottom line: there is no exception to the rule because it would make successful compilation depend on the value (rather the type) of a constant.
EDIT
#HeartWare pointed out that constant expressions of the form A DIV B are not allowed in some languages, when B is 0, and cause compilation to fail. Hence changing of a constant could cause compilation errors in some other place. Which is, IMHO, unfortunate. But it is certainly good to restrict such things to the unavoidable.
The confusion is that storing a constant value into a local variable is not one atomic instruction on every architecture the C is designed to be run on. The processor the code runs on matters more than the compiler in this case. For example, on ARM where each instruction can not carry a complete 32 bits constant, storing an int in a variable needs more that one instruction. Example with this pseudo code where you can only store 8 bits at a time and must work in a 32 bits register, i is a int32:
reg = 0xFF; // first instruction
reg |= 0xFF00; // second
reg |= 0xFF0000; // third
reg |= 0xFF000000; // fourth
i = reg; // last
You can imagine that if the compiler wants to optimize it may interleave the same sequence twice, and you don't know what value will get written to i; and let's say that he is not very smart:
reg = 0xFF;
reg |= 0xFF00;
reg |= 0xFF0000;
reg = 0xFF;
reg |= 0xFF000000;
i = reg; // writes 0xFF0000FF == -16776961
reg |= 0xFF00;
reg |= 0xFF0000;
reg |= 0xFF000000;
i = reg; // writes 0xFFFFFFFF == -1
However in my tests gcc is kind enough to recognize that the same value is used twice and generates it once and does nothing weird. I get -1, -1
But my example is still valid as it is important to consider that even a constant may not be as obvious as it seems to be.
Behavior is commonly specified as undefined if there is some conceivable reason why a compiler which was trying to be "helpful" might do something which would cause totally unexpected behavior.
In the case where a variable is written multiple times with nothing to ensure that the writes happen at distinct times, some kinds of hardware might allow multiple "store" operations to be performed simultaneously to different addresses using a dual-port memory. However, some dual-port memories expressly forbid the scenario where two stores hit the same address simultaneously, regardless of whether or not the values written match. If a compiler for such a machine notices two unsequenced attempts to write the same variable, it might either refuse to compile or ensure that the two writes cannot get scheduled simultaneously. But if one or both of the accesses is via a pointer or reference, the compiler might not always be able to tell whether both writes might hit the same storage location. In that case, it might schedule the writes simultaneously, causing a hardware trap on the access attempt.
Of course, the fact that someone might implement a C compiler on such a platform does not suggest that such behavior shouldn't be defined on hardware platforms when using stores of types small enough to be processed atomically. Trying to store two different values in unsequenced fashion could cause weirdness if a compiler isn't aware of it; for example, given:
uint8_t v; // Global
void hey(uint8_t *p)
{
moo(v=5, (*p)=6);
zoo(v);
zoo(v);
}
if the compiler in-lines the call to "moo" and can tell it doesn't modify
"v", it might store a 5 to v, then store a 6 to *p, then pass 5 to "zoo",
and then pass the contents of v to "zoo". If "zoo" doesn't modify "v",
there should be no way the two calls should be passed different values,
but that could easily happen anyway. On the other hand, in cases where
both stores would write the same value, such weirdness could not occur and
there would on most platforms be no sensible reason for an implementation
to do anything weird. Unfortunately, some compiler writers don't need any
excuse for silly behaviors beyond "because the Standard allows it", so even
those cases aren't safe.
C++17 defines stricter evaluation rules. In particular, it sequences function arguments (although in unspecified order).
N5659 §4.6:15
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. [ Note: Indeterminately sequenced evaluations cannot overlap, but either could
be executed first. —end note ]
N5659 § 8.2.2:5
The
initialization of a parameter, including every associated value computation and side effect, is indeterminately
sequenced with respect to that of any other parameter.
It allows some cases which would be UB before:
f(i = -1, i = -1); // value of i is -1
f(i = -1, i = -2); // value of i is either -1 or -2, but not specified which one
The fact that the result would be the same in most implementations in this case is incidental; the order of evaluation is still undefined. Consider f(i = -1, i = -2): here, order matters. The only reason it doesn't matter in your example is the accident that both values are -1.
Given that the expression is specified as one with an undefined behaviour, a maliciously compliant compiler might display an inappropriate image when you evaluate f(i = -1, i = -1) and abort the execution - and still be considered completely correct. Luckily, no compilers I am aware of do so.
It looks to me like the only rule pertaining to sequencing of function argument expression is here:
3) When calling a function (whether or not the function is inline, and whether or not explicit function call syntax is used), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function.
This does not define sequencing between argument expressions, so we end up in this case:
1) If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined.
In practice, on most compilers, the example you quoted will run fine (as opposed to "erasing your hard disk" and other theoretical undefined behavior consequences).
It is, however, a liability, as it depends on specific compiler behaviour, even if the two assigned values are the same. Also, obviously, if you tried to assign different values, the results would be "truly" undefined:
void f(int l, int r) {
return l < -1;
}
auto b = f(i = -1, i = -2);
if (b) {
formatDisk();
}
The assignment operator could be overloaded, in which case the order could matter:
struct A {
bool first;
A () : first (false) {
}
const A & operator = (int i) {
first = !first;
return * this;
}
};
void f (A a1, A a2) {
// ...
}
// ...
A i;
f (i = -1, i = -1); // the argument evaluated first has ax.first == true
Actually, there's a reason not to depend on the fact that compiler will check that i is assigned with the same value twice, so that it's possible to replace it with single assignment. What if we have some expressions?
void g(int a, int b, int c, int n) {
int i;
// hey, compiler has to prove Fermat's theorem now!
f(i = 1, i = (ipow(a, n) + ipow(b, n) == ipow(c, n)));
}
This is just answering the "I'm not sure what "scalar object" could mean besides something like an int or a float".
I would interpret the "scalar object" as a abbreviation of "scalar type object", or just "scalar type variable". Then, pointer, enum (constant) are of scalar type.
This is a MSDN article of Scalar Types.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Undefined Behavior and Sequence Points
How the statement x=x++ + y++; executes to the value 3?
I was wondering how printf work in a case like this:
int i = 0;
printf("%4d%4d", i++, i);
Result is 0 1
in another case
int i = 0;
printf("%4d%4d", i, i++);
Result is 1 0
This has nothing to do with printf, and everything to do with the order in which the parameters are evaluated and the way the compiler executes your code. The behavior is undefined, and the results will depend on your compiler, calling convention, and phase of the moon.
In both your examples, the rules of pre/post incrementing are taking precedence. Your particular compiler understands that it must use the value of i before evaluating the increment, and is giving precedence to the parameter that invokes a function call over the one that doesn't. Your second usage of the variable i is causing the compiler to insert an intermediary statement in the process of calling printf,
It's important to note that i++ doesn't mean (as is commonly taught) "increment i after executing this line", it just means "increment i at some point after giving me its value, and before executing the next line". That's a lot of wiggle room for the compiler to do what is formally called "undefined behavior."
As #Als points out in a comment, you've managed to combine both undefined and unspecified behaviors in one line of code.
This is not due to printf it's due to you being in a case of undefined behaviour
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 25 days ago.
x = 1;
std::cout << ((++x)+(++x)+(++x));
I expect the output to be 11, but it's actually 12. Why?
We explain it by expecting undefined behaviour rather than any particular result. As the expression attempts to modify x multiple times without an intervening sequence point its behaviour is undefined.
As others have said, the C and C++ standards do not define the behaviour that this will produce.
But for those people who don't see why the standards would do such a thing, let's go through a "real world" example:
1 * 2 + 3 + 4 * 5
There's nothing wrong with calculating 1 * 2 + 3 before we calculate 4*5. Just because multiplication has a higher precedence than addition doesn't mean we need to perform all multiplication in the expression before doing any addition. In fact there are many different orders you validly could perform your calculations.
Where evaluations have side effects, different evaluation orders can affect the result. If the standard does not define the behaviour, do not rely on it.
This is actually undefined. C++ doesn't define explicitly the order of execution of a statement so it depends on the compiler and this syntax shouldn't be used.
The code snippet will invoke Undefined behavior in both C/C++.Read about Sequence Point from here.
In my opinion
cout<<((++x)+(++x)+(++x));
compiler first run prefix ++x so value of x becomes
x=2
now by ++x, x will become
x=3
after ++x
x=4
Now its time to add values of x
x+x+x=4+4+4
x+x+x=12