C unary operators (increment)

Programming, for all ages and all languages.
Post Reply
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

C unary operators (increment)

Post by Neo »

I'm having trouble understanding how this works.
Can anyone explain the output of this?

Code: Select all

#include<stdio.h>

main()
{
   int a,i;
   i=5;
   a=i++ + ++i;
   printf("\na=%d i=%d",a,i);
   i=5;
   i=a=i++ + ++i;
   
   printf("\na=%d i=%d",a,i);
}
The output is

Code: Select all

a=12 i=7
a=12 i=13
Only Human
mystran

Re:C unary operators (increment)

Post by mystran »

There are a few problems here.
First problem is that it is undefined what happens if you use a varible again in the same expression where it's incremented/decremented with ++/--, unless ofcourse boolean short-circuiting rules force certain evaluation order.

So basicly, "i++ + ++i" could do almost anything, including but not limited to:
- get value of first i, increment i, increment it again and get the final value
- get value of first i, increment the second i, get it's value, the increment the first i.
- increment the second i, get it's value, get first i's value, increment it
- get value of second i + 1, get first i, store i+2
- well... you get the point

In fact, you might even get different results with the same compiler depending on optimization flags and/or surrounding code. If the compiler decides to duplicate the code somewhere in order to optimize parts of it away in certain special case, you might even get different results for the same code in the same binary, depending on which instance of the codepath was taken.

In short: when using post/pre-increment/decrement, do not ever depend on evaluation order beyond the rules that post-increment returns the "old" value and pre-increment returns the "incremented" value. Even "i + ++i" is equally bad, and totally undefined as is "i = ++i".

There is a complete section for discussing most this "feature" in comp.lang.c FAQ http://www.eskimo.com/~scs/C-faq/s3.html
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:C unary operators (increment)

Post by Solar »

mystran wrote:
Even "i + ++i" is equally bad, and totally undefined as is "i = ++i".
Use i * 1 + 1 and ++i instead.

Sorry, couldn't resist. 8)

But mystran is very right, and since you're obviously learning about postfix and prefix right now, a bit of slightly related advice: If you have the choice, like in for (int i; i < size; ++i), always use prefix increment / decrement.

Doesn't look like much, but once you ascend into the higher levels (like, non-trivial C++ iterators), it does make a difference. (In fact, you'd be creating a temporary object with the postfix, which you wouldn't with the prefix.)

If that doesn't make sense right now, tuck it away somewhere and look at it again when you're learning about iterators. ;)
Every good solution is obvious once you've found it.
mystran

Re:C unary operators (increment)

Post by mystran »

Excuse me, Solar, but whether one uses pre or post operators when the value isn't used is a matter of choice. Keeping it consistent is a good idea though.

Also, the issue isn't whether you use post or pre-operators. The issue is that C standard declares behaviour undefined when you modify variable more than once in a single expression, or take a value and modify the same variable in expressions where the order of evaluation isn't explicitly specified.

In short, "i+++++i" (which parses i++ + ++i btw) does not need to return a value at all. The behaviour is undefined which means a standard comforming compiler can do anything it wants with that including but not limited to crashing your computer, formatting your hard-drive, causing your program to order pizza..
mystran

Re:C unary operators (increment)

Post by mystran »

From http://www.eskimo.com/~scs/C-faq/q3.2.html (or other comp.lang.c FAQ mirrors)
[...]

The behavior of code which contains multiple, ambiguous side effects has always been undefined. (Loosely speaking, by ``multiple, ambiguous side effects'' we mean any combination of ++, --, =, +=, -=, etc. in a single expression which causes the same object either to be modified twice or modified and then inspected. This is a rough definition; see question 3.8 for a precise one, and question 11.33 for the meaning of ``undefined.'') Don't even try to find out how your compiler implements such things (contrary to the ill-advised exercises in many C textbooks); as K&R wisely point out, ``if you don't know how they are done on various machines, that innocence may help to protect you.''

References: K&R1 Sec. 2.12 p. 50
K&R2 Sec. 2.12 p. 54
ANSI Sec. 3.3
ISO Sec. 6.3
CT&P Sec. 3.7 p. 47
PCS Sec. 9.5 pp. 120-1
If you are forced to make such a excercise, asnwer "the program ordered pizza with pepperony and onions" and quote the above. As for the referred question 11.33:
Briefly: implementation-defined means that an implementation must choose some behavior and document it. Unspecified means that an implementation should choose some behavior, but need not document it. Undefined means that absolutely anything might happen. In no case does the Standard impose requirements; in the first two cases it occasionally suggests (and may require a choice from among) a small set of likely behaviors.
Emphasis mine.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:C unary operators (increment)

Post by Solar »

mystran wrote: Excuse me, Solar, but whether one uses pre or post operators when the value isn't used is a matter of choice.
In C, yes (AFAICS). In C++, no.

In C++, the operator '++' can be overloaded to do whatever the programmer considered intuitive for a '++' to do for the class in question, which can be a very non-trivial operation on a quite complex data structure. (Like, "annihilate next planet on list" for an object of the DeathStar class. ;) )

Now, prefix '++' takes the next planet from the list, annihilates it, and returns a reference to 'this' (the DeathStar). Easy enough.

But postfix '++' takes the next planet from the list, annihilates it, and must return a reference to a DeathStar that has not yet annihilated that planet.

There's a copy constructor you don't want to call out of carelessness. ;) And that's why you should grow into the habit of, all other things equal, using prefix '++' and '--'. You never know when you'll have to handle that DeathStar class. ;)
Every good solution is obvious once you've found it.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:C unary operators (increment)

Post by Candy »

Solar wrote: In C, yes (AFAICS). In C++, no.

In C++, the operator '++' can be overloaded to do whatever the programmer considered intuitive for a '++' to do for the class in question, which can be a very non-trivial operation on a quite complex data structure. (Like, "annihilate next planet on list" for an object of the DeathStar class. ;) )

Now, prefix '++' takes the next planet from the list, annihilates it, and returns a reference to 'this' (the DeathStar). Easy enough.

But postfix '++' takes the next planet from the list, annihilates it, and must return a reference to a DeathStar that has not yet annihilated that planet.

There's a copy constructor you don't want to call out of carelessness. ;) And that's why you should grow into the habit of, all other things equal, using prefix '++' and '--'. You never know when you'll have to handle that DeathStar class. ;)
Considering the death star size, you don't want to copy that without reason... On the other hand, I'd choose *star for destructing a planet and ++star for going to the next one. Still, you'd have to return a DeathStar at the old planet when doing a star++, as opposed to a DeathStar at the new planet (where you are) with ++star.
mystran

Re:C unary operators (increment)

Post by mystran »

I pretty much believe that if you overload ++ as such an operation, you definitely have problems worse than a few copy-constructors.

That said, I can see this as a problem with a bignum code in an application handling really big numbers or such, where overloading ++ is quite logical.

I appreciate you pointing this out.

That said, I believe I got something else wrong as well:
"i+++++i" parses as "(i++)++ +i" (excercise: why?), which ofcourse doesn't compile (excercise: why?). What I was trying to write was "i+++ ++i". Anyway, it still can order pizza, so who cares if such things compile or not (unless you are trying to make your program order pizza ofcourse).
Gaurav

Re:C unary operators (increment)

Post by Gaurav »

actually if you have marked then unary operator's precendence in rigth to left means in i++ + ++i second ++i will be computed first followed by i++. and as you know C compiler generates pointer and adds at last instead of adding intermediate results directly. so in a= i++ + ++i first ++i will be computed and i will become 6. after that compiler will come at i++ and sees post-increment and so it computes a like value at pointer to i + value at pointer to i means 6 + 6 = 12 and after that it will increment i as it is left to execute and answer will be 13.
where in second problem it computes a as described above and then assigns value of a to i means 'i' will become 12 and after that statement executed remaining post-increment will be executed and results in value of 'i' to 13.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:C unary operators (increment)

Post by Candy »

Neo wrote: I'm having trouble understanding how this works.
Can anyone explain the output of this?

Code: Select all

#include<stdio.h>

main()
{
   int a,i;
   i=5;
   a=i++ + ++i;
   printf("\na=%d i=%d",a,i);
   i=5;
   i=a=i++ + ++i;
   
   printf("\na=%d i=%d",a,i);
}
The output is

Code: Select all

a=12 i=7
a=12 i=13
back to the origin question... GCC probably does:

Code: Select all

- Preincrements
- The expression(s) and assignment(s)
- Postincrements
This brings i to 6, then puts i (plusplus) plus (plusplus) i into a (remove the (plusplus)'es, they're used before and after this). Then, i is incremented again, to bring 7. a = 6+6 = 12.

The second one, i is incremented once. It is then 6. i+i is assigned to a, a becoming 12. a is assigned to i, i becoming 12. Then the postincrements are done, bringing i to 13.

Conclusion, as you can also guess by the above story, don't use an increment/decrement where you have to use the same value in the same expression again, and NEVER use a post and a preincrement in the same expression. Also NEVER assign to the pre/postincremented value.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:C unary operators (increment)

Post by Solar »

Dudes, and there I thought we had this one pinned down... 8)
if you have marked then unary operator's precendence in rigth to left means in i++ + ++i second ++i will be computed first followed by i++
C99, 6.5 Expressions, paragraph 2 f.:
Between the previous and the 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 grouping of operators and operands is indicated by the syntax. Except as specified later (for the function-call (), &&, ||, ?:, and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified.
Boldface is mine.

Write i++ + ++i, you die. Period.
Every good solution is obvious once you've found it.
Post Reply