Interesting about - -x

Started by
19 comments, last by ToohrVyk 16 years, 4 months ago

int main()
{
    int x = 100;
    printf("%d %d %d",--x, --x, --x);
    return 0;
}
Its output

97 98 99
Isn't it suppose to display 99 98 97? Another thing:

int main()
{
    int x = 100;
    x = --x + --x;
    printf("%d", x);
    return 0;
}
Its output

196
Isn't 99 + 98 = 197? Any explaination?
DinGY
Yesterday is history.Tomorrow is a mystery. Today is a gift"
Advertisement
"C++ requires that the arguments to a function be completely evaluated
(and all side-effects posted) prior to entering the function, but the
implementation is free to evaluate the arguments in any order."

So you are basically relying on undefined behavior.

The answer to your second question:

In your second example your compiler may evaluate the expression left of '+' first, or the expression right of '+'. Lets say it performs the left side first:

-First you perform 100-1, which is 99. This result is assigned to the variable 'x'
-Next you perform 99-1, which is 98. This result is assigned to the same variable 'x'
-As a result you evaluate x=98+98, which equals 196
The C++ standard makes no guarantees about the order of evaluation in expressions containing several increment/decrement operators. For this reason, it's a good idea to keep such operations to expressions of their own.

I don't think there's anything too shocking about the results you're getting regarding the decrement operator, but I'm surprised that printf seems to parse its arguments in reverse-order.

The second example does exactly what I would expect: the -- operator precedes the = assignment, and so x is decremented twice before summing the result with itself. Though I'm not sure that this is reliable behaviour.
Ring3 Circus - Diary of a programmer, journal of a hacker.
Sequence points. Modifying the same variable twice between sequence points is undefined. Since neither the commas in the function call or the plus operator are sequence points, both are undefined behaviour.
Quote:Original post by OrangyTang
both are undefined behaviour.

In a nutshell, your program might launch nuclear missiles. So please don't run it!
1) The variables are pushed into the stack from "RIGHT TO LEFT." For example, when you're calling printf("%d", a, b, c), the actual function call will be...

push c
push b
push a
push offset "%d"
call _printf
(_cdecl functions readjust the stack by themselves.)

So when you call printf("%d %d %d", --x, --x, --x); the rightmost variable is subtracted first, then the middle one, then the left one. This is not undefined behavior. lol...

2) This one's a little tricky.

x = --x + --x;

-- directives are executed prior to = directive. So, --x is executed twice before the statement evaluates the total sum.

x = 98 + 98 = 196

Does this make sense? This one does not go from left to right either. x is subtracted twice in the statement, so x becomes 98. Then the two Xs are added into x. To help you understand, try these statements.

x = --x;
x = --x;
x = x + x;

Hope this helped.
Here's the actual disassembly code from Visual Studio 2005. :)


2)

/////// int x = 100;
0041138E mov dword ptr [x],64h <-- x = 64h ( 16 * 6 + 4 = 100 )

/////// x = --x + --x;

//Step 1) Load x into eax register
00411395 mov eax,dword ptr [x]

//Step 2) Subtract 1 from eax register
00411398 sub eax,1

//Step 3) Store the value back to x
0041139B mov dword ptr [x],eax


//Step 4) Load x into ecx register
0041139E mov ecx,dword ptr [x]

//Step 5) Subtract 1 from ecx register
004113A1 sub ecx,1

//Step 6) Store the value back to x
004113A4 mov dword ptr [x],ecx


//Step 7) Load x into edx register
004113A7 mov edx,dword ptr [x]

//Step 8) edx = edx + x
004113AA add edx,dword ptr [x]

//Step 9) Store the value back to x
004113AD mov dword ptr [x],edx


In conclusion, x is subtracted twice before the addition.
Quote:Original post by Sangha Im
So when you call printf("%d %d %d", --x, --x, --x); the rightmost variable is subtracted first, then the middle one, then the left one. This is not undefined behavior. lol...

It most certainly is. Today MSVC does it this way. Tomorrow it might decide to reorder things, particularly if it's inlining functions. Maybe it'll identify an unreferenced variable and move the decrement to after the statement. Maybe it won't. This is what it means for behavior to be undefined. Obviously it does something, but what it does should on no account be relied upon.
I think I get you guy mean now. Thanks you

DinGY
Yesterday is history.Tomorrow is a mystery. Today is a gift"
Consider an expression which evaluates "--x" twice. Do the two expressions evaluate to 99 and 98 (as in the printf example) or to 98 and 98 (as in the addition example) ? There is no steadfast language-level rule for this, because the language standard has explicitly mentioned that such constructs are illegal. In short, don't use them, because there's no way to tell reliably what will happen.

Sangha Im:

Your explanation is wrong. Such a level of incorrectness as the one in your reply can only come from someone who is utterly ignorant of the notion of sequence points. Because of this, you are not a reliable source of information for order-of-evaluation and side-effect resolution in C and C++. I will politely suggest that you get a clue about this area of programming by reading the link OrangyTang provided (quoted above for your viewing pleasure) and all its cited sources.

Quote:This is not undefined behavior. lol...


You've just described two situations which evaluated '--x' twice. In the first, the result is 99 and 98, while in the second it is 98 and 98. How can you call this defined?

This topic is closed to new replies.

Advertisement