Welcome to MSDN Blogs Sign in | Join | Help

Two posers for you

What is the output of the following code, and why?

[Update: By “why“, I mean “what part of the C# spec controls this behavior?“]

class Test
{
  public static void Main()
  {
    int z = 2;
    z += ++z+5*z++;
    System.Console.WriteLine("Yak! {0}", z);
  }
}

What about this code?

class Test
{
  public static void Main()
  {
    int z = 2;
    z += (5*z++)+(++z);
    System.Console.WriteLine("Yak! {0}", z);
  }
}

Extra credit: What is the defined output for C++, and why?

Published Monday, April 19, 2004 3:04 PM by ericgu
Filed under: , ,

Comments

Monday, April 19, 2004 3:43 PM by Scott Wisniewski

# re: Two posers for you

The C++ output is implementation defined, because the C++ standard doesn't specify when in an expression the "set" portion of any increment instructions should be executed.
Monday, April 19, 2004 3:44 PM by John

# re: Two posers for you

The answer is "it doesn't matter" right?

Because no-one would be evil enough to write a statement that used the ++ operator in an expression!

Right? Seriously, you guys.. :)
Monday, April 19, 2004 3:50 PM by Darren Neimke

# re: Two posers for you

Thanks for that Eric... very intruiging :-)

You failed my code review though!
Monday, April 19, 2004 4:03 PM by Doug McClean

# re: Two posers for you

Is it "Yak! 28"?
Monday, April 19, 2004 7:13 PM by MasterMaq.NET

# .NET Happenings #28

Monday, April 19, 2004 4:14 PM by Scott Wisniewski

# re: Two posers for you

20 and 16.
It apears that in both cases the += is using the value of Z at the start of the expression.
Monday, April 19, 2004 4:19 PM by AndrewSeven

# re: Two posers for you

Poser one : the guy pretending to be programmer.
Poser two : the senior who fixed it into the second version.

The output of the code might be a job opening but is more likely to produce a lecture.


http://weblogs.asp.net/andrewseven/articles/Ramblings.aspx
Monday, April 19, 2004 4:21 PM by Scott Wisniewski

# re: Two posers for you

Let me clarify....

It apears that in both cases, variable += expression is doing this...

1. get the value of "variable", store it in a temp register
2. evaluate expression
3. add the evaluated expresion to the value of Z in the temp register
4. set the value of Z with the value from the temp register

Monday, April 19, 2004 4:24 PM by haacked

# re: Two posers for you

The first is 20
z = 2 + 3 + 5(3) = 20

The second is 16
z = (10 + 1)+(2)+ 3

Monday, April 19, 2004 5:40 PM by Milan Negovan

# re: Two posers for you

Hang on, let me paste it in Visual Studio... :)
Monday, April 19, 2004 5:58 PM by Sean Chase

# re: Two posers for you

My SWAG is that the pre-increment expression is firing after all of the orders of operation, so you get something like this:

int z = 2;
z += 2/*++z*/ + 5 * 3 /*z++*/;
++z;
System.Console.WriteLine("Yak! {0}", z);

I won't bother with the others unless I find out I'm on the right track. Fun stuff!
Monday, April 19, 2004 5:58 PM by Sean Chase

# re: Two posers for you

My SWAG is that the pre-increment expression is firing after all of the orders of operation, so you get something like this:

int z = 2;
z += 2/*++z*/ + 5 * 3 /*z++*/;
++z;
System.Console.WriteLine("Yak! {0}", z);

I won't bother with the others unless I find out I'm on the right track. Fun stuff!
Monday, April 19, 2004 6:13 PM by Sean Chase

# re: Two posers for you

Holy double post batman - sorry about that. OK, maybe I'm chasing up the wrong tree again, but I'm thinking that the second is another order of operations vs. increment/decrement expression:

int z = 2;
z += (5 * /*z*/2) /*++operator*/+ 1 + /*value of z*/(2);
++z;//then this happens???

Monday, April 19, 2004 7:36 PM by Wes

# re: Two posers for you

Here is what I found in the C# spec that governs the rules for this problem.

Sec 7.13.2 Compound Assignment states "If the return type of the selected operator is implicitly convertible to the type of x, the operation is evaluated as x = x op y, except that x is evaluated only once"

Sec 7.2 Operators states "The order of evaluation of operators in an expression is determined by the precedence and associativity of the operators"

Sec 7.2.1 Operator precedence and associativity states "Except for the assignment operators, all binary operators are left-associative, meaning that operations are performed from left to right."

Sec 7.6.1 Prefix operator states "The result of ++x is the value of x after the operation"

Sec 7.5.9 Postfix operator states "The result of x++ is the value of x before the operation"

Working through the expression using the precedence table in section 7.2.1

z += ++z + 5 * z++;
z = z + (++z + 5 * z++); by 7.13.2
z = 2 + (++z + 5 * z++);
z = 2 + (++2 + 5 * z++);
z = 2 + (3 + 5 * z++); // z has value 3 now
z = 2 + (3 + 5 * 3++);
z = 2 + (3 + 5 * 3); // z has value 4 now
z = 2 + (3 + 15);
z = 2 + (18);
z = 20; // z has value 20 now

So the output is "Yak! 20"

Looking at the second expression

z += (5 * z++) + (++z);
z = z + ((5 * z++) + (++z));
z = 2 + ((5 * z++) + (++z));
z = 2 + ((5 * 2++) + (++z));
z = 2 + ((5 * 2) + (++z)); // z has value 3 now
z = 2 + ((10) + (++z));
z = 2 + (10 + (++3));
z = 2 + (10 + (4)); // z has value 4 now
z = 2 + (14);
z = 16; // z has value 16 now

So the output is "Yak! 16"

As far as the in C++ it is undefined because to the order of evaluation is undefined, from section 6.2.2 Evaluation Order in Programming Languages Third Edition by Bjarne Stroustrup. That section also states that it is undefined because better code can be generated in the absence of restrictions on expression evaluation order.

Wes
Monday, April 19, 2004 7:39 PM by Wes

# re: Two posers for you

Sorry the C++ book is "The C++ Programming Language" Third Edition. Just in case someone didn't know. :)
Monday, April 19, 2004 7:42 PM by Jiho Han

# re: Two posers for you

16 each?
Monday, April 19, 2004 10:53 PM by Omer van Kloeten

# re: Two posers for you

The first answer would be 22, since it's defined [1] that the operator precedence will be the primary operator (z++ // will be calculated in next line), followed by the unary operator (++z), the multiplication operator (5*z), the additive operator (+) and lastly the assignment operator.

The second answer would be 16, since the precedence will be the primary operator (z++ // will be calculated in next line), followed by the multiplication operator (5*z), the unary operator (++z), the additive operator (+) and lastly the assignment operator.

[1] http://msdn.microsoft.com/library/en-us/csspec/html/vclrfcsharpspec_7_2_1.asp
Tuesday, April 20, 2004 12:22 AM by Marc Hoeppner

# re: Two posers for you

Isn't it funny that z += z++; produces the same result as z += z;

;)

Tuesday, April 20, 2004 3:48 AM by thomas woelfer

# re: Two posers for you

Eric,

frankly: it doesn't matter. code like that should not be written (and i know that you know). write-only code like that needs some serious rewriting. :-)

WM_MY0.02$
thomas woelfer
Tuesday, April 20, 2004 8:13 AM by Kael Rowan

# This seems odd...

Wes is right about how the expression gets evaluated. What's interesting though is that the order of evaluation doesn't quite seem to match what one would expect from the chart in 7.2.1. Lets take a simpler example by removing the compound expression and comparing the two following expressions:

- [1] -
int z = 2;
int y = z + ++z;

- or [2] -

int z = 2;
int y = ++z + z;

According to the chart, primary-expressions are evaluated first, and then unary-expressions after. A primary-expression can be a primary-no-array-creation-expression, which can be a simple-name, which is an identifier (such as z). A unary-expression comes after, which could be a pre-increment-expression (such as ++z). Therefore the statements should be evaluated as follows:

[1]
x = z + ++z; // start
x = 2 + ++z; // primary-expression evaluated
x = 2 + 3; // unary-expression evaluated, z is now 3
x = 5; // what you would expect

[2]
x = ++z + z; // start
x = ++z + 2; // primary-expression evaluated
x = 3 + 2; // unary-expression evaluated, z is now 3
x = 5; // same answer as in [1]

If you run this through version 7.10.3052.4 of the C# compiler you'll actually get something different for [2]:

x = ++z + z; // start
x = 3 + z; // unary-expression evaluated first! z is now 3
x = 3 + 3; // the primary-expression 'z' is evaluated which is now 3
x = 6; // Yak!

Hopefully I'm just misinterpreting the spec somehow, but shouldn't simple-name expressions such as 'z' be evaluated before unary-expressions such as ++z?

-Kael
Tuesday, April 20, 2004 8:28 AM by Wes

# re: Two posers for you

Kael,
Actually I don't think that z is evaluated first in fact I would expect that your second example would have an answer 6. Unless I'm reading the spec wrong I think the unary and prefix operator have the same precedence so they are evaluated left-to-right.

Wes
Tuesday, April 20, 2004 9:53 AM by Robert Kozak

# re: Two posers for you

Definately 20 and 16.

This isnt all that hard.

First:
int z = 2;
z += ++z+5*z++;


unary-expressions first from left to right

z = 2 + (3) + (5 * 3);

Then the mulitplication
z = 2 + 3 + 15

Then Addition
z = 20

Second one:

int z = 2;
z += (5*z++)+(++z);

brackets first

z = 2 + ((5*2)++) + (++z);

then unary
z = 2 + 10++ + (3);

then addition
z = 2 + 11 + 3;
z = 16


Simple no?


Tuesday, April 20, 2004 9:55 AM by Kael Rowan

# re: Two posers for you

Wes,

Is the occurance of z without any operators applied (such as x = z) considered having a unary operator applied? I guess my question is where to identifiers without any unary operators fall in the operator precedence and associativity table? I intrepreted the spec to mean that an identifier (i.e. simple-name, i.e. primary-no-creation-expression, i.e. primary-expression) came first under the "Primary" category in the operator precedence and associativity table:

primary-expression: // "Primary" Category
primary-no-array-creation-expression
array-creation-expression

primary-no-array-creation-expression:
literal
simple-name
parenthesized-expression
member-access
invocation-expression
element-access
this-access
base-access
post-increment-expression
post-decrement-expression
object-creation-expression
delegate-creation-expression
typeof-expression
checked-expression
unchecked-expression

simple-name:
identifier // z

unary-expression: // "Unary" Category
primary-expression
+ unary-expression
- unary-expression
! unary-expression
~ unary-expression
pre-increment-expression // ++z
pre-decrement-expression
cast-expression

Here's a link to the docs I'm looking at:

ms-help://MS.VSCC.2003/MS.MSDNQTR.2003JUL.1033/csspec/html/vclrfcsharpspec_7_2_1.htm

-Kael
Tuesday, April 20, 2004 10:34 AM by Wes

# re: Two posers for you

Following a left-to-right derivation of the grammar rules I would assume that ++z is evaluated first:

expression
conditional-expression
conditional-or-expression
conditional-and-expression
inclusive-or-expression
exclusive-or-expression
and-expression
equality-expression
relational-expression
shift-expression
additive-expression
additive-expression + multiplicative-expression
multiplicative-expression + multiplicative-expression
unary-expression + multiplicative-expression
pre-increment-expression + multiplicative-expression
++unary-expression + multiplicative-expression
++primary-expression + multiplicative-expression
++simple-name + multiplicative-expression
++identifier + multiplicative-expression
++z + multiplicative-expression
++z + unary-expression
++z + primary-expression
++z + simple-name
++z + identifier
++z + z

I don't think the precedence matters in this case because there is no conflict, meaning that the '+' in the middle is of lower precedence than both so you need to evaluate the arguments for the '+' from left-to-right.

If I'm wrong here please someone correct me.

Wes
Tuesday, April 20, 2004 10:55 AM by Sean Chase

# re: Two posers for you

Just for kicks, compile the code and open the assembly with Anakrino. The output is nowhere near being correct. :-)
Tuesday, April 20, 2004 11:24 AM by Kael Rowan

# re: Two posers for you

Hi Wes,

I like the explicit grammar construction you provided, but I'm trying to figure out how that shows us that ++z would be evaluated first. How does expression evaluation follow grammer production? I would have assumed that on line 12 of your production it would have evaluated multiplicative-expression first since it has higher precedence over additive-expression. But if it constantly goes from left-to-right, the following production would produce the wrong evaluation:

x + y * z

expression
conditional-expression
conditional-or-expression
conditional-and-expression
inclusive-or-expression
exclusive-or-expression
and-expression
equality-expression
relational-expression
shift-expression
additive-expression
additive-expression + multiplicative-expression
multiplicative-expression + multiplicative-expression
unary-expression + multiplicative-expression
primary-expression + multiplicative-expression
simple-name + multiplicative-expression
identifier + multiplicative-expression
x + multiplicative-expression
x + multiplicative-expression * unary-expression
x + unary-expression * unary-expression
x + primary-expression * unary-expression
x + simple-name * unary-expression
x + identifier * unary-expression
x + y * unary-expression
x + y * primary-expression
x + y * simple-name
x + y * identifier
x + y * z

Here we all know that y * z should be evaluated first, but which point in the grammar production explains this (and correspondingly where is the corresponding point in the x = ++z + z production that explains why ++z is evaluated before z)?

Thanks again for explaining this. I hope others reading this thread are learning from it as much as I am! :)

-Kael
Tuesday, April 20, 2004 2:25 PM by TheChaseMan's Frenetic SoapBox

# Math, post-increment, pre-increment, and C#

Tuesday, April 20, 2004 11:35 AM by Kael Rowan

# re: Two posers for you

Sean,

I took your advice and opened it with Lutz's .NET Reflector and it's nowhere near correct either:

int num1;
num1 = 2;
num1 = (num1 + 1);
num1 = (num1 + 1);
num1 = (num1 + ((num1 + 1) + (5 * num1)));
Console.WriteLine("Yak! {0}", num1);

Hmm, have we discovered some new form of obfuscation? (As if the original code isn't obfuscated enough already)

-Kael
Tuesday, April 20, 2004 12:00 PM by Dave

# re: Two posers for you

I just think it's bloody hilarious that this much work has to go into decoding two lines. Definitely not a Pit of Success.
Tuesday, April 20, 2004 12:01 PM by Wes

# re: Two posers for you

Kael,

With your particular example x + y * z, y has two possible operators to be used with thus there is a conflict and * has higher precedence so it used.

What typically happens with these type expressions is a parse tree is created using the grammar rules and then that tree is evaluated using a pre-order traversal. I would draw out your parse tree but it is kind of hard to do in the comments :)

Essentially what is happening for your expression is that you are going to add x to the result of the multiplicative-expression which is y * z. Where as with the ++z + z you are going to add the result of the pre-increment-expression to the result of the multiplicative-expression.

I think if you look at the parse trees for these expressions it will help your understanding.

Wes
Thursday, April 22, 2004 2:36 AM by Robin Debreuil

# re: Two posers for you

Very cool! I really like how this forces you to actually understand expressions (err, forces someone like Wes to explain it to us ; ).

I've recently made a C# compiler[1] using antlr, and expressions were really hard (for me) to get right. I thought it was all debugged, but the above code acutally caught two errors - one with multiple classes without a namespace, and one converting the tree to a C#Dom (it missed the very last preinc expressions inside parens). There actually might be more to that though (just x=(++y); seems to have a problem too) -- bugs are like the mice in the house, if you see two, there are 60 more in the walls. I dearly hope I don't have to revisit the expression grammar(!), but thanks for the hostile code in any case : ).

The project I'm working on exports C# to the swf (flash) stack environment. Interestingly the above code in actionscript (flash's language) also gives 20 and 16. I guess it is normal enough to convert the += like that then..? I really fear these tiny differences in the two environments, it is really hard to test for them, or even know you need to. I know it is all nicely laid out in the C# spec, but you hate pulling out your magnifying glass on a document that size ; ).

Anyway, I think quirky code like this is really useful. Of course you wouldn't use it or write it, but it really helps solidify your 'mental image' of what is going on in your code. And like in this case, it often exposes one of those little 'truths in a nutshell' (like marc's z += z++; -> 4) that can one day save untold suffering from being cast upon your bacon.

Thanks for the post,
Robin

[1]no home yet, just a beta at http://blog.debreuil.com

# Eric Gunnerson s C Compendium Two posers for you | Weak Bladder

New Comments to this post are disabled
 
Page view tracker