48

Looking at this question and trying out some of the code:

int x = 100;

while ( 0 <-------------------- x )
{
    printf("%d ", x);
}

I attempted to compile with gcc and got the following error:

file.c: In function 'main':
file:c:10:27: error: lvalue required as decrement operand
 while ( 0 <-------------------- x )

But compiling with g++ works. Why is this code valid in C++ but not C?

Community
  • 1
  • 1
MD XF
  • 7,860
  • 7
  • 40
  • 71
  • 79
    Because C and C++ are two different languages. In other words, C and C++ are not the same language. – Kerrek SB Feb 20 '17 at 23:28
  • 1
    Because the downto operator `<--` can be stretched in C++ many times if you want to decrease faster: `<----` is downtoby2, `<--------------------` is downtoby10 – chqrlie Feb 20 '17 at 23:32
  • 4
    @chqrlie Circular reasoning. Q: Why does water come out of my tap and not Pepsi? A: Because taps can be used to easily access water. – user253751 Feb 20 '17 at 23:45
  • 6
    In C, you can work around it by writing `while (0 < (x -= 10))`. – dan04 Feb 20 '17 at 23:58
  • 18
    Alternately, to keep the fancy style of the OP, `while (0 < (x +=-+-+- 10))` – chqrlie Feb 21 '17 at 00:00
  • @chqrlie You didn't tell me that either. You merely restated what the question was asking about. – user253751 Feb 21 '17 at 00:29
  • 1
    The thread you posted needs a big sign with sarcasm/irony/humor above it, most things there are not to be used. I would consider @dan04 's style `while (0 < (x -= 10))` superior in any way.... Just because things are possible doesn't mean they are good. – Kami Kaze Feb 21 '17 at 08:21
  • @jamesqf That `--a` return `a` looks like a sound choice to me. – Quentin Feb 21 '17 at 08:56
  • 4
    This decrementing style is seriously one of the ugliest things I've ever seen. *washes eyes with acid* – Peter Badida Feb 21 '17 at 11:25
  • 9
    _"But compiling with g++ works. Why is this code valid in C++ but not C?"_ - Just because g++ (or any other compiler) accepts it doesn't automatically mean it's valid C++ code. Never ever forget that. – marcelm Feb 21 '17 at 12:29
  • 1
    @KeyWeeUsr It's just [controlling decrement speed based on arrow length.](http://stackoverflow.com/a/27672749/7292857) – MD XF Feb 21 '17 at 16:12
  • 1
    @dan04 I think your suggestion `while (0 < (x -= 10))` is better because it is more readable and maintainable. – Joe Feb 21 '17 at 16:34
  • @Kami Kaze: I even find that confusing. Clearer to write "while ((x -= 10) > 0)". At least I normally think left to right - maybe people from cultures whose native languages are written right to left would disagree. And another question: for what value of n is it more efficient to decrement n times, than to subtract n? My guess is not more than 2. – jamesqf Feb 22 '17 at 18:54
  • @jamesqf I won't bother discussing if you should "reverse" the statement. It is just the same. Both are better than `--------------i` though – Kami Kaze Feb 23 '17 at 13:14
  • 1
    @Redesign and it should be punished with copying the C++ standard by hand, if you ever write this in a program. I hope you did understand that the whole thing is just a joke. – Kami Kaze Feb 23 '17 at 13:17
  • 1
    @KamiKaze I **certainly** did. – MD XF Feb 23 '17 at 16:53

1 Answers1

91

In C, --x is a value, not an lvalue. Its effect is to decrement x, and evaluate to the newly assigned value of x. Since --x is not an lvalue, it cannot be decremented.

In C++, --x is an lvalue, not an rvalue. Its effect is to decrement x, and evaluate to x as an lvalue. Since --x is an lvalue again, it can be decremented again.

The reason why it makes sense for --x to be an lvalue in C++ is because C++ introduced reference types. Given

void f(int &);
int i;

it may make sense to call f(--i), which passes i by reference after decrementing it.

Since C doesn't have reference types, there's little point in --i being an lvalue. Historically, it never was, and unlike C++, C never gained a compelling reason to change the rules.

Note that C++ required more extensive changes than making --x an lvalue to actually let it work. Making --x an lvalue, without anything else, would make --x undefined behaviour, because there would not be a sequence point between the modification to x and the subsequent lvalue-to-value conversion. Even more clearly so for ----x. C++ had to modify the sequencing rules to make it work. In C, modifications to the sequencing rules might cause problems for existing compilers to conform to the new rules, so such modifications would likely be rejected unless there's a big benefit.

  • 8
    You could still want to say something like `f(&--x)`. I'm not sure I buy your reason why "there's no point" in C. – Kerrek SB Feb 20 '17 at 23:23
  • 4
    @KerrekSB Fair point, but there's still little point. I'd say `f(&--x)` is less likely to be what someone actually wants to write than `f(--x)`. Regardless, C also has a problem that changes to the rules would be problematic for existing implementations, I added a bit on that. –  Feb 20 '17 at 23:34
  • C++ did not require any sequencing changes to make `--x` an lvalue. The pre-C++11 rule about sequence points pertains to reads and writes, not to lvalue-to-rvalue conversions. – M.M Feb 21 '17 at 01:33
  • 7
    The behaviour of `----x` changed in C++11 (well-defined after, undefined before) – M.M Feb 21 '17 at 01:40
  • 8
    If you really want to do `f(&--x)` in C, you can do `f((--x,&x))`. – G-Man Says 'Reinstate Monica' Feb 21 '17 at 03:06
  • 5
    I'm not sure about the historical background here, but IMO the most compelling case for making assignment return an lvalue is that for user-defined classes, you really don't want to return a copy. Then everything else is just consistency. – T.C. Feb 21 '17 at 13:36
  • @T.C. That comment probably depends to be its own answer, although I suppose one could argue that the rules don't have to be the same for built-in types and classes that overload `++`. – Barmar Feb 21 '17 at 18:26
  • @T.C. What you say makes sense as well, and if you or someone else were to say you do remember that that's the real reason, I'd believe you. This is what I think I remember reading at one point, but I could be misremembering, or I could have read it from someone else who didn't know the history either. –  Feb 21 '17 at 21:17
  • People who write code like `f(&--x)` should get fired immediately. – juzzlin Nov 21 '19 at 16:41