Tuesday, October 25, 2005

 

What Does "++x++" Mean?

As one of my team's know-it-alls, I had a brief language-lawyer question presented to me today: What does the expression "++x++" mean in the C++ programming language? (All you non-programmers, and most programmers, will want to stop reading now.)

The C++ language, like its predecessor C, includes an operator "++" which increments the value contained in a variable. (The C++ language includes this operator in its name—meaning that it somehow "one better" than C.) The ++ operator can be prefix, as in "++x", or postfix, as in "x++". The difference is that the prefix operator first increments the variable and then returns its new value, whereas the postfix increments the variable, but returns its original value. So, for example, this code

  int x = 10;
  int result = ++x;  // prefix
  cout << "x = " << x << "; result = " << result << endl;

will generate the output "x = 11; result = 11", whereas this code:

  int x = 10;
  int result = x++;  // postfix
  cout << "x = " << x << "; result = " << result << endl;

will generate the output "x = 11; result = 10".

There is also a "--" operator, which works like "++" except that it decrements the variable rather than incrementing it. All this discussion of ++ also applies to --.

So, the question is, can you use the prefix and postfix operators at the same time on a variable, and what would the output be?

  int x = 10;
  unknown_type result = ++x++;    // prefix and postfix
  cout << "x = " << x << "; result = " << result << endl;

Some unthinking people guess that the variable x would be incremented twice, and then make even worse guesses about what result is going to be. Nope. The above won't even compile, as it is not valid C++. If you try to compile it, you will probably get an error message about an "invalid lvalue."

To understand why, first we need to define what an lvalue is. Simply stated, an lvalue (pronounced "ell-value") is an expression that can appear on the left side of an assignment statement. For example, in this code:

  int a, *p, **q;
  int& r = a;
  a = 10;
  p = &a;
  *p = 11;
  q = &p;
  **q = 12;
  r = 13;

the expressions a, p, *p, q, **q, and r are all lvalues. In contrast, 10, &a, and &p are not lvalues. You can't write an assignment statement that starts with "10 = ..." or "&a = ..."; it just wouldn't make sense.

Earlier, I wrote that the ++ operator increments a variable. Technically, it can increment any lvalue, which it does by retrieving the value from its location, adding one to it, and storing the new value back to the location. (Optimizations can shorten that series of steps; I'm describing the logical operation.) So, "++x" is roughly equivalent to "x = x + 1" (or "x += 1"). If p is a pointer variable, then "*p" is an lvalue, and we can use the expression "++(*p)" to mean "*p = *p + 1". Another way of thinking of an lvalue is that it is some identified location in memory where we can store a value.

So now, let's look at "++x++". Our first question is about operator precedence: does the prefix operator take effect first, or does the postfix operator take effect first? The answer is that the postfix operator has higher precedence, so "++x++" is evaluated as "++(x++)".

Now let's pretend to be a computer and try to interpret and evaluate this. To make it concrete we'll assume that the initial value of x is 15. We evaluate the subexpression "(x++)", which sets x to 16, and returns the original value 15. Now, all we have to do is plug that result into the overall expression, and we have our answer.

But wait, how do we evaluate "++15"? We can't. Remember, ++ only works on lvalues, and 15 is not an lvalue. It's as if we are trying to evaluate "15 = 15 + 1", which is nonsense in C++. If you thought our new super-expression would be "++(x)", with x equal to 16, note that the result of "x++" is 15, not an lvalue.

So, "++x++" is not a legal expression, if x is an int, or long, or another such built-in integer type. Is there any way to define an x such that it would be a legal expression? One way is to create a user-defined type that provides definitions for the prefix and postfix ++, like this:

  class DoublePlus
  {
  public:
    // prefix operator
    DoublePlus operator++()    { return *this; }
    
    // postfix operator
    DoublePlus operator++(int) { return *this; }
  };

  DoublePlus x;

Then the expression "++x++" will compile. It won't do anything, as written here, but one could define whatever effects are desired for the two operators. Heck, one could even make them increment a value, but that's beside the point.

By the way, note the bizarre unused int argument in the second operator++ declaration. That's how the compiler tells the difference between the definitions of the prefix operator and the postfix operator. This is one of those elegant features that really endears C++ to its users.

So anyway, by creating a user-defined type, I can make "++x++" a valid expression, and make it do whatever I want. I can't figure out any way to do it without a user-defined type. I've tried various combinations of pointers and references, but the best I can come up with is something like "++*x++".

If anyone knows how to do it, or can prove it impossible, please let me know.


Comments:
omgwtfru talking about? im gonna wtfbbqpwn urazz for this crap!

The Pirate / Ninja debate rages for all eternity.
 
Post a Comment

<< Home

This page is powered by Blogger. Isn't yours?