Operator precedence and operator associativity rules in c++ [duplicate] - c++

This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 9 years ago.
I do not understand why the output of following program is 63:
#include <iostream>
int main() {
int a = 20;
a += a + ++a;
std::cout << a;
}
I was expecting it to be 61. What exactly a += a + ++a; does?

Standard says: "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" (5 Expressions, §4), i.e. the following:
a += a + ++a
yields undefined behavior just like:
a = ++a;
does already. It also says: "the prior value shall be accessed only to determine the value to be stored", i.e. if you want to change a, you can use a in the same expression just to retrieve the previous value:
a = a + 1; // OK
... "otherwise the behavior is undefined."

You're triggering undefined behavior and there is no 'correct' answer. Your compiler can chose what order to evaluate the arguments of the plus operator.

it looks like ++a is evaluating before the rest of the expression, so it's as though a is 21` in a statement like
a += a + a;
at any rate, don't use ++a inside of an arithmetic expression like that anyway. It's confusing for people, and is probably undefined behavior

Related

C++ "value++" causes warning but "value+1" doesn't? [duplicate]

This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 3 years ago.
The code:
int a = 0;
a = ++a % 5;
causes the warning:
warning: operation on 'a' may be undefined [-Wsequence-point]
a = ++a % 5;
~~^~~~~~~~~
with various compilers such as gcc when compiling with -Wall
Yet this code, works fine?
int a = 0;
a = (a + 1) % 5;
Why is this a warning, and can it safely be ignored?
Wrapping it in brackets etc. doesn't seem to make the warning go away.
Edit: For clarification, I was using C++17 compiler when seeing these warning messages.
a = ++a % 5;
a is modified two times. Before C++11, this is undefined behavior — it is not specified that the increment is committed before the assignment. Since C++11, the side effect of the pre-increment on the RHS is guaranteed to be evaluated first, and a is guaranteed to be 1.
a = (a + 1) % 5;
Here, a is only modified one time. The resulted a is guaranteed to be 1.
Per comment: operator precedence does not determine the order of evaluation. Although assignment has higher precedence, the order of evaluation is still unspecified (prior to C++11).
EDIT:
Before C++11: Because with ++a you're modifying a while you're modifying a through assignment, therefore undefined behavior.
After C++11: See #L.F.'s answer.

why i = ++i + 2 is undefined behavior? [duplicate]

This question already has answers here:
New Sequence Points in C++11
(2 answers)
So why is i = ++i + 1 well-defined in C++11?
(3 answers)
Closed 4 years ago.
I've read something about order of evaluation and I understand some mistakes caused by order of evaluation.
My basic rule comes from a text and example:
Order of operand evaluation is independent of precedence and associativity.
In most cases, the order is largely unspecified.
So for expression like this: int i = f1() * f2();
f1 and f2 must be called before the multiplication can be done. After all, it is their results that are multiplied. However, we have no way of knowing whether f1 will be called before f2 or vice versa.
Undefined behavior examples:
int i = 0;
cout << i << " " << ++i << endl;
How I understand: I treat i and ++i as a function. I don't know which evaluates first, so the first i could be 0 or 1 and (the rule) makes sense.
while(beg != s.end())
*beg = toupper(*beg++); //Just another example.
I think the key to understand this is to treat each operand as a "evaluation unit", and one don't know order of evaluation within these units but can know order in every single unit.
But for i = ++i + 2 reference here, Why is it wrong? I can't explain with my own conclusion.
The left i is used as a lvalue and not a pointer. ++i simply rewrite the original value and doesn't change the storage address. What could be wrong if it evaluates first or latter? My rule fails here.
Quite long but try to provide enough background info, thank for your patience.
I don't know sequence point which is mentioned frequently in answers.. So I think I need to read something about it first. Btw, the debate is not very helpful, for a newbie simply want to know why is it considered wrong, like before C++11?
I find this answer Undefined behavior and sequence points explain well why i = ++i + 2 is undefined behaviour before C++11
C++11 has new sequencing rules. In particular, for a pre-increment (++i) the side effect (writing the new value) is sequenced-before the further use of the new, incremented value. Since the assignment i= is sequenced-after the evaluation of its right-hand side, this means the write ++i is transitively sequenced-before the write i=(++i + 2)
It would be another matter for i=(i++ + 2). For post-increment, the side effect is sequenced-after, which means the two assignments are no longer sequenced relatively to each other. That IS undefined behavior.
Your two "subfunctions" in i = ++i + 2 are an explicit assignment made by the = operator and an implicit assignment done by the ++ operator.
The preincrement operator is defined to return an incremented value of the variable, and this definitely shall be used for addition (performed by the + operator). However, it was not defined, when the incremented value should be stored back into i.
As a result, it was undefined whether the final value of i is old_i incremented plus 2 or just old_i incremented.

C programming unary operator precedence [duplicate]

This question already has an answer here:
Difference between a+++++b and a++ + ++b [duplicate]
(1 answer)
Closed 7 years ago.
#include <stdio.h>
int main()
{
int c=10,b;
b=++c+++c;
printf("%d",b);
return 0;
}
Could someone please let me know,why it is throwing compilation error?
The gibberish is tokenised as
++ c ++ + c
and parsed as
((++c)++) + c
This tries to increment the rvalue yielded by ++c, which isn't allowed. You can only increment an lvalue (or a class type, in C++).
Even if it were allowed, this would give undefined behaviour: you'd have an unsequenced modification and use of the value of c.
The compilation error would be solved if you put a space in ++c + ++c
b = ++c + ++c;
But that just fixes the compilation error. What you are doing is Undefined Behavior. Trying to change the value of c more than once in the same expression using ++ will lead to undefined Behavior.
Read Why are these constructs (using ++) undefined behavior?

Increment and decrement with pointer arrays [duplicate]

This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 8 years ago.
My teacher provided me with this code and it returns 31,40, but I am unable to figure out why. What is the reason for it returning what it does?
void main() {
int *ptr;
int arr[5] = { 10, 20, 30, 40, 50 };
ptr = &arr[3];
cout << ++*ptr-- << ", " << *ptr;
}
cout << ++*ptr-- << ", " << *ptr;
is
operator <<(cout.operator <<(++*ptr--), ", ").operator <<(*ptr);
The problem can be reduced to:
f(f(ptr--), ptr)
whereas order of evaluation between f(ptr--) and ptr is unspecified (and more specificaly between ptr-- and ptr).
So you got undefined behavior for the given code.
The C++ standard states
Section 1.9/15 [intro.execution] : Except where noted, evaluations of operands of individual operators and of subexpressions of individual
expressions are unsequenced. (...) If a side effect on a scalar object is unsequenced relative to either another side effect on the
same scalar object or a value computation using the value of the same
scalar object, the behavior is undefined.
++*ptr-- and *ptr are unsequenced subexpressions of the same expression using the same object: nothing guarantees that they are evaluated from left to right. So according to the standard, this results in undefined behaviour. Your result tend to show that your compiler chooses to evaluate first *ptr and then ++*ptr--.
Edit: ++*ptr-- is ++(*ptr--)). Here the operand of operator ++ also uses object ptr on which -- does a side effect. So this is undefined behaviour as well. It appears that in your case, the compiler first evaluates *ptr-- which results in 40 and a decremented ptr, and then applies ++ on the dereferenced decremented pointer (i.e. 30 incremented by 1).

Why is this statement not changin the array? [duplicate]

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 9 years ago.
int a[]={1,2,3,5};
int i=1;
a[++i]=a[i];
int j;
for(j=0;j<4;j++)
{
printf("%d",a[j]);
}
output:1235;
why the output is 1225 and not 1335.
I executed this program on codeblocks. In a[++i]=a[i], Right to left assignment will be their,leading to a[2]=a[1]. Correct me if i am wrong.
Because a[++i]=a[i]; is undefined behavior.
A sequence point is a point in time at which the dust has settled and all side effects which have been seen so far are guaranteed to be complete. The sequence points listed in the C standard are:
at the end of the evaluation of a full expression (a full
expression is an expression statement, or any other expression which
is not a subexpression within any larger expression);
at the ||, &&, ?:, and comma operators; and
at a function call (after the evaluation of all the arguments, and just before the actual call).
The standard states that
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.
a[++i]=a[i]; // this is undefined
If you only want to change single element of the array ... do it by referencing it directly:
int a[]={1,2,3,5};
int i=1;
a[i]++; // this will increment the ith element of the array by 1
int j;
for(j=0;j<4;j++)
{
printf("%d",a[j]);
}
Output:
1335
a[++i]=a[i]; is undefined behavior. Because according to C99 section 6.5 paragraph 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.72) Furthermore, the prior value shall be read only to
determine the value to be stored.73)
= is not a sequence point. Check annex C.
You are modifying the value i one time, but "the prior value shall be read only to determine the value to be stored" is violated as you do a[++i].
Check Footnote 73) for an example of what the paragraph says.
73)This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i] = i;
Therefore what the outcome will be cannot be determined. For different run and/or across different computers you can get different results. Such kind of expressions should not be used in C programming.
a[++i] = a[i] is undefined behavior. look-up this presentation.