9401

After reading Hidden Features and Dark Corners of C++/STL on comp.lang.c++.moderated, I was completely surprised that the following snippet compiled and worked in both Visual Studio 2008 and G++ 4.4.

Here's the code:

#include <stdio.h>
int main()
{
    int x = 10;
    while (x --> 0) // x goes to 0
    {
        printf("%d ", x);
    }
}

Output:

9 8 7 6 5 4 3 2 1 0

I'd assume this is C, since it works in GCC as well. Where is this defined in the standard, and where has it come from?

Josu Goñi
  • 804
  • 1
  • 7
  • 20
GManNickG
  • 459,504
  • 50
  • 465
  • 534

26 Answers26

9102

--> is not an operator. It is in fact two separate operators, -- and >.

The conditional's code decrements x, while returning x's original (not decremented) value, and then compares the original value with 0 using the > operator.

To better understand, the statement could be written as follows:

while( (x--) > 0 )
Mark Amery
  • 110,735
  • 57
  • 354
  • 402
Charles Salvia
  • 48,775
  • 12
  • 118
  • 138
  • 1
    I've seen it jokingly referred to as the "downto" operator (https://codegolf.stackexchange.com/questions/16226/i-need-a-program-where-the-user-inputs-an-array-of-doubles-and-the-program-outpu/16232#16232) – Moshe Bildner May 19 '21 at 13:26
3437

Or for something completely different... x slides to 0.

while (x --\
            \
             \
              \
               > 0)
     printf("%d ", x);

Not so mathematical, but... every picture paints a thousand words...

Dr. Gut
  • 1,240
  • 2
  • 20
unsynchronized
  • 4,609
  • 2
  • 29
  • 40
2457

That's a very complicated operator, so even ISO/IEC JTC1 (Joint Technical Committee 1) placed its description in two different parts of the C++ Standard.

Joking aside, they are two different operators: -- and > described respectively in §5.2.6/2 and §5.9 of the C++03 Standard.

Kirill V. Lyadvinsky
  • 89,955
  • 22
  • 127
  • 208
1399

x can go to zero even faster in the opposite direction:

int x = 10;

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

8 6 4 2

You can control speed with an arrow!

int x = 100;

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

90 80 70 60 50 40 30 20 10

;)

MD XF
  • 7,062
  • 7
  • 34
  • 64
doc
  • 7,500
  • 5
  • 42
  • 67
1343

It's equivalent to

while (x-- > 0)

x-- (post decrement) is equivalent to x = x-1 so, the code transforms to:

while(x > 0) {
    x = x-1;
    // logic
}
x--;   // The post decrement done when x <= 0
Oskar Skog
  • 323
  • 4
  • 14
Jay Riggs
  • 51,115
  • 9
  • 133
  • 146
571

It's

#include <stdio.h>

int main(void) {
  int x = 10;
  while (x-- > 0) { // x goes to 0
    printf("%d ", x);
  }
  return 0;
}

Just the space makes the things look funny, -- decrements and > compares.

Derek Wang
  • 9,675
  • 4
  • 14
  • 36
RageZ
  • 25,094
  • 11
  • 63
  • 76
452

The usage of --> has historical relevance. Decrementing was (and still is in some cases), faster than incrementing on the x86 architecture. Using --> suggests that x is going to 0, and appeals to those with mathematical backgrounds.

Matt Joiner
  • 100,604
  • 94
  • 332
  • 495
  • 508
    Not exactly true. Decrementing and Incrementing take the same amount of time, the benefit of this is that comparison to zero is very fast compared to comparison versus a variable. This is true for many architectures, not just x86. Anything with a JZ instruction (jump if zero). Poking around you can find many "for" loops that are written backwards to save cycles on the compare. This is particularly fast on x86 as the act of decrementing the variable set the zero flag appropriately, so you could then branch without having to explicitly compare the variable. – burito Dec 30 '09 at 05:16
  • 31
    Well, decrementing toward zero means you only have to compare against 0 per loop iteration, while iterating toward n means comparing with n each iteration. The former tends to be easier (and on some architectures, is automatically tested after every data register operation). – Joey Adams Apr 12 '10 at 15:07
  • 1
    This would be better as a footnote in another answer or a comment - it clearly doesn't explain what `-->` means, which is what was asked. – Bernhard Barker May 22 '15 at 12:55
  • 8
    In x86 ASM, the `LOOP
    ` decreases the `ECX` register, then jumps to `
    ` unless the decrementing of `ECX` resulted in zero. Decrementing the loop counter towards zero allows the compiler to generate a single `LOOP` instruction, whereas incrementing or counting to other values requires separate INC/DEC/ADD/SUB, compare, and conditional jump instructions. Modern compilers can often convert other loops to a `counter --> 0` loop if the value of `counter` isn't used in the loop.
    – Mark K Cowan Jul 08 '15 at 11:26
  • 4
    Continuing my previous comment: `MOV ECX, value`, `@start:`, ``, `LOOP @start` is an x86 ASM equivalent for `counter = value - 1; while (counter --> 0) { ; }`. Note that it will barf if `value` is initially zero, so an extra check is needed pre-loop. – Mark K Cowan Jul 08 '15 at 11:32
390

Utterly geek, but I will be using this:

#define as ;while

int main(int argc, char* argv[])
{
    int n = atoi(argv[1]);
    do printf("n is %d\n", n) as ( n --> 0);
    return 0;
}
Mateen Ulhaq
  • 18,406
  • 13
  • 75
  • 112
Escualo
  • 36,702
  • 18
  • 79
  • 122
  • 3
    I know it looks way cool, but I fear it's deceptive. The reason you're writing C++ instead of Machine Language is b/c you want to convey your intent to the next guy reading your code. This construct violates the principle of least surprise. It is a mental "trip hazard." – StevePoling Mar 07 '21 at 19:43
384
while( x-- > 0 )

is how that's parsed.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Grumdrig
  • 14,990
  • 11
  • 53
  • 68
334

One book I read (I don't remember correctly which book) stated: Compilers try to parse expressions to the biggest token by using the left right rule.

In this case, the expression:

x-->0

Parses to biggest tokens:

token 1: x
token 2: --
token 3: >
token 4: 0
conclude: x-- > 0

The same rule applies to this expression:

a-----b

After parse:

token 1: a
token 2: --
token 3: --
token 4: -
token 5: b
conclude: (a--)-- - b

I hope this helps to understand the complicated expression ^^

NguyenDat
  • 4,079
  • 3
  • 43
  • 45
284

This is exactly the same as

while (x--)
Fghj
  • 334
  • 6
  • 23
Good Person
  • 1,427
  • 2
  • 22
  • 40
  • 166
    Shouldn't this be `for(--x++;--x;++x--)`? – Mateen Ulhaq Dec 04 '11 at 21:32
  • 10
    @DoctorT that's what `unsigned` is for – Cole Johnson Mar 23 '13 at 18:39
  • 4
    `while (x --> 0)` is **not** the same as `while (x--)` if `x` has a signed type, the first loop does not execute at all if `x` has a negative value but the second iterates many times until it hits undefined behavior when `x` reaches `INT_MIN`. – chqrlie Mar 12 '21 at 17:14
250

Anyway, we have a "goes to" operator now. "-->" is easy to be remembered as a direction, and "while x goes to zero" is meaning-straight.

Furthermore, it is a little more efficient than "for (x = 10; x > 0; x --)" on some platforms.

Grijesh Chauhan
  • 52,958
  • 19
  • 127
  • 190
Test
  • 1,643
  • 1
  • 11
  • 10
  • 20
    Goes to cant be true always especially when value of x is negative. – Ganesh Gopalasubramanian Nov 13 '09 at 03:22
  • 16
    The other version does not do the same thing - with `for (size_t x=10; x-->0; )` the body of the loop is executed with 9,8,..,0 whereas the other version has 10,9,..,1. It's quite tricky to exit a loop down to zero with an unsigned variable otherwise. – Pete Kirkham Jun 21 '10 at 08:57
  • 5
    I think this is a little bit misleading... We don't have a literally "goes to" operator, since we need another `++>` to do the incremental work. – tslmy Jun 15 '13 at 02:49
  • 23
    @Josh: actually, overflow gives undefined behavior for `int`, so it could just as easily eat your dog as take `x` to zero if it starts out negative. – SamB Dec 06 '13 at 06:57
  • 4
    This is a very important idiom to me for the reason given in the comnmet by @PeteKirkham, as I often need to do decreasing loops over unsigned quantities all the way to `0`. (For comparison, the idiom of omitting tests for zero, such as writing `while (n--)` instead for unsigned `n`, buys you nothing and for me greatly hampers readability.) It also has the pleasant property that you specify _one more_ than the initial index, which is usually what you want (e.g., for a loop over an array you specify its size). I also like `-->` without space, as this makes the idiom easy to recognise. – Marc van Leeuwen Aug 30 '14 at 20:08
  • ... Actually, I somewhat regret that writing `while(00)`, and the former is usually not what you want. On the other hand, at least in C++, you can make it descend twice as fast with `while(0 – Marc van Leeuwen Aug 30 '14 at 20:16
  • 1
    `x=10; while(x --> 0)` is not the same as `for(x=10; x>0; x--)`... it would on the other hand be the same as `for(x=10-1; x=>0; x--)` . – Horse SMith Nov 21 '14 at 02:12
  • 1
    Well, also `while(0 <=-- x)`. But this's getting silly(er) :p – Narfanar May 26 '15 at 07:57
  • 1
    With any level of compiler optimisation, there is **no difference in efficiency.** The assembly output is identical. – Artelius Aug 21 '20 at 01:36
227

This code first compares x and 0 and then decrements x. (Also said in the first answer: You're post-decrementing x and then comparing x and 0 with the > operator.) See the output of this code:

9 8 7 6 5 4 3 2 1 0

We now first compare and then decrement by seeing 0 in the output.

If we want to first decrement and then compare, use this code:

#include <stdio.h>
int main(void)
{
    int x = 10;

    while( --x> 0 ) // x goes to 0
    {
        printf("%d ", x);
    }
    return 0;
}

That output is:

9 8 7 6 5 4 3 2 1
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Sajad Bahmani
  • 16,531
  • 27
  • 81
  • 105
186

My compiler will print out 9876543210 when I run this code.

#include <iostream>
int main()
{
    int x = 10;

    while( x --> 0 ) // x goes to 0
    {
        std::cout << x;
    }
}

As expected. The while( x-- > 0 ) actually means while( x > 0). The x-- post decrements x.

while( x > 0 ) 
{
    x--;
    std::cout << x;
}

is a different way of writing the same thing.

It is nice that the original looks like "while x goes to 0" though.

John Odom
  • 1,100
  • 2
  • 19
  • 35
Stone Mason
  • 1,974
  • 2
  • 15
  • 18
  • 5
    The result is only undefined when you're incrementing/decrementing the same variable more than once in the same statement. It doesn't apply to this situation. – Tim Leaf May 05 '10 at 15:30
  • 14
    `while( x-- > 0 ) actually means while( x > 0)` - I'm not sure what you were trying to say there, but the way you phrased it implies the `--` has no meaning whatsoever, which is obviously very wrong. – Bernhard Barker May 22 '15 at 12:28
  • To drive the point home from @Dukeling, this answer is *not the same* as the original post. In the original post, `x` will be `-1` after it leaves the loop, while in this answer, `x` will be `0`. – Mark Lakata Feb 24 '20 at 16:41
155

There is a space missing between -- and >. x is post decremented, that is, decremented after checking the condition x>0 ?.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
  • 45
    The space is not missing - C(++) ignores whitespace. –  Aug 02 '12 at 19:16
  • 28
    @H2CO3 This isn't true in general. There are places where white space must be used to separate tokens, e.g. in `#define foo()` versus `#define foo ()`. – Jens Apr 25 '13 at 21:16
  • 31
    @Jens How about: "The space is not missing - C(++) ignores unnecessary white space."? – Kevin P. Rice Dec 04 '13 at 20:35
144

-- is the decrement operator and > is the greater-than operator.

The two operators are applied as a single one like -->.

Mateen Ulhaq
  • 18,406
  • 13
  • 75
  • 112
sam
  • 356
  • 1
  • 3
  • 10
  • 13
    They're _applied_ as the 2 separate operators they are. They're only _written_ misleadingly to look like "a single one". – underscore_d Nov 12 '16 at 17:56
134

It's a combination of two operators. First -- is for decrementing the value, and > is for checking whether the value is greater than the right-hand operand.

#include<stdio.h>

int main()
{
    int x = 10;

    while (x-- > 0)
        printf("%d ",x);

    return 0;
}

The output will be:

9 8 7 6 5 4 3 2 1 0            
John Odom
  • 1,100
  • 2
  • 19
  • 35
Rajeev Das
  • 1,503
  • 4
  • 17
  • 21
125

Actually, x is post-decrementing and with that condition is being checked. It's not -->, it's (x--) > 0

Note: value of x is changed after the condition is checked, because it post-decrementing. Some similar cases can also occur, for example:

-->    x-->0
++>    x++>0
-->=   x-->=0
++>=   x++>=0
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
AndroidLearner
  • 1,290
  • 7
  • 23
  • 40
  • 6
    Except that ++> can hardly be used in a while(). A "goes up to..." operator would be ++ is a happy coincidence. – Florian F Sep 01 '14 at 09:46
  • 2
    @BenLeggiero That could 'work' in the sense of generating code that does something (while infuriating readers who don't like faux-clever code), but the semantics are different, as its use of predecrement means it will execute one fewer iteration. As a contrived example, it would never execute the loop body if `x` started at 1, but `while ( (x--) > 0 )` would. {edit} Eric Lippert covered both in his C# 4 release notes: https://blogs.msdn.microsoft.com/ericlippert/2010/04/01/some-last-minute-new-c-4-0-features/ – underscore_d Nov 12 '16 at 17:57
123

C and C++ obey the "maximum munch" rule. The same way a---b is translated to (a--) - b, in your case x-->0 translates to (x--)>0.

What the rule says essentially is that going left to right, expressions are formed by taking the maximum of characters which will form an valid expression.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Pandrei
  • 4,683
  • 3
  • 22
  • 42
30

Why all the complication?

The simple answer to the original question is just:

#include <stdio.h>

int main()
{
    int x = 10;
    while (x > 0)
    {
        printf("%d ", x);
        x = x-1;
    }
}

It does the same thing. I am not saying you should do it like this, but it does the same thing and would have answered the question in one post.

The x-- is just shorthand for the above, and > is just a normal greater-than operator. No big mystery!

There are too many people making simple things complicated nowadays ;)

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Garry_G
  • 149
  • 4
  • 12
  • 19
    This question is not about complications, but about ** Hidden Features and Dark Corners of C++/STL** – pix Oct 27 '16 at 15:32
  • 25
    The program here gives different output than original because x here is decremented after printf. That demonstrates well how "simple answers" are usually Incorrect. – Öö Tiib May 13 '17 at 09:30
  • 3
    `The OP's way: 9 8 7 6 5 4 3 2 1 0` and `The Garry_G way: 10 9 8 7 6 5 4 3 2 1` – Anthony Dec 15 '17 at 18:33
  • 3
    It doesn't do the same thing. Move your `x=x-1` before `printf` then you can say "it does the same thing". – CITBL Jan 05 '19 at 17:05
27

Conventional way we define condition in while loop parenthesis"()" and terminating condition inside the braces"{}", but this -- & > is a way one defines all at once. For example:

int abc(){
    int a = 5
    while((a--) > 0){ // Decrement and comparison both at once
        // Code
    }
}

It says, decrement a and run the loop till the time a is greater than 0

Other way it should have been like:

int abc() {
    int a = 5;
    while(a > 0) {
        a = a -1 // Decrement inside loop
        // Code
    }
}

Both ways, we do the same thing and achieve the same goals.

S.S. Anne
  • 13,819
  • 7
  • 31
  • 62
Zohaib Ejaz
  • 351
  • 4
  • 18
  • 5
    This is incorrect. The code in the question does: 'test-write-execute' (test first, write new value, execute the loop), your example is 'test-execute-write'. – v010dya Jul 14 '17 at 19:07
  • @v010dya Fixed the answer, now it's `test-write-execute` as in the question, thanks for pointing out! – Kotauskas May 12 '19 at 10:59
  • @S.S.Anne Your edit is still wrong. The `a--` after the while shouldn't be there. – Stefan Fabian Dec 29 '20 at 09:49
  • *Both ways, we do the same thing and achieve the same goals.* Not really: both loops iterate 5 times, but the final value of `a` after the loop completes is `-1` in the first case and `0` in the second. – chqrlie Mar 12 '21 at 12:20
20

(x --> 0) means (x-- > 0).

  1. You can use (x -->)
    Output: 9 8 7 6 5 4 3 2 1 0
  1. You can use (-- x > 0) It's mean (--x > 0)
    Output: 9 8 7 6 5 4 3 2 1
  1. You can use
(--\
    \
     x > 0)

Output: 9 8 7 6 5 4 3 2 1

  1. You can use
(\
  \
   x --> 0)

Output: 9 8 7 6 5 4 3 2 1 0

  1. You can use
(\
  \
   x --> 0
          \
           \
            )

Output: 9 8 7 6 5 4 3 2 1 0

  1. You can use also
(
 x 
  --> 
      0
       )

Output: 9 8 7 6 5 4 3 2 1 0

Likewise, you can try lot of methods to execute this command successfully.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Kalana
  • 4,683
  • 6
  • 22
  • 46
11
char sep = '\n'  /1\
; int i = 68    /1  \
; while (i  ---      1\
                       \
                       /1/1/1                               /1\
                                                            /1\
                                                            /1\
                                                            /1\
                                                            /1\
                            /           1\
                           /            1 \
                          /             1  \
                         /              1   \
                         /1            /1    \
                          /1          /1      \
                           /1        /1        /1/1> 0) std::cout \
                              <<i<<                               sep;

For larger numbers, C++20 introduces some more advanced looping features. First to catch i we can build an inverse loop-de-loop and deflect it onto the std::ostream. However, the speed of i is implementation-defined, so we can use the new C++20 speed operator <<i<< to speed it up. We must also catch it by building wall, if we don't, i leaves the scope and de referencing it causes undefined behavior. To specify the separator, we can use:

 std::cout \
           sep

and there we have a for loop from 67 to 1.

lxr196
  • 68
  • 1
  • 7
2

This --> is not an operator at all. We have an operator like ->, but not like -->. It is just a wrong interpretation of while(x-- >0) which simply means x has the post decrement operator and this loop will run till it is greater than zero.

Another simple way of writing this code would be while(x--). The while loop will stop whenever it gets a false condition and here there is only one case, i.e., 0. So it will stop when the x value is decremented to zero.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Ankit Mishra
  • 323
  • 3
  • 13
2

Here -- is the unary post decrement operator.

 while (x-- > 0) // x goes to 0
 {
     printf("%d ", x);
 }
  • In the beginning, the condition will evaluate as (x > 0) // 10 > 0
  • Now because the condition is true, it will go into the loop with a decremented value x-- // x = 9
  • That's why the first printed value is 9
  • And so on. In the last loop x=1, so the condition is true. As per the unary operator, the value changed to x = 0 at the time of print.
  • Now, x = 0, which evaluates the condition (x > 0 ) as false and the while loop exits.
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Neeraj Bansal
  • 338
  • 4
  • 21
1

--> is not an operator, it is the juxtaposition of -- (post-decrement) and > (greater than comparison).

The loop will look more familiar as:

#include <stdio.h>
int main() {
    int x = 10;
    while (x-- > 0) { // x goes to 0
        printf("%d ", x);
    }
}

This loop is a classic idiom to enumerate values between 10 (the excluded upper bound) and 0 the included lower bound, useful to iterate over the elements of an array from the last to the first.

The initial value 10 is the total number of iterations (for example the length of the array), and one plus the first value used inside the loop. The 0 is the last value of x inside the loop, hence the comment x goes to 0.

Note that the value of x after the loop completes is -1.

Note also that this loop will operate the same way if x has an unsigned type such as size_t, which is a strong advantage over the naive alternative for (i = length-1; i >= 0; i--).

For this reason, I am actually a fan of this surprising syntax: while (x --> 0). I find this idiom eye-catching and elegant, just like for (;;) vs: while (1) (which looks confusingly similar to while (l)). It also works in other languages whose syntax is inspired by C: C++, Objective-C, java, javascript, C# to name a few.

chqrlie
  • 98,886
  • 10
  • 89
  • 149
  • 1
    I wonder why this answer was automatically made a community wiki... – chqrlie Mar 12 '21 at 17:20
  • 1
    You have enough reputation to know: a) this is a community wiki question, so all answers are community wiki, and b) this answer is just a duplication of the plethora of existing answers, on a decade old question. – GManNickG Mar 12 '21 at 20:42
  • 1
    @GManNickG: I was unaware of the implicit connection between questions and answers for the community wiki status, not everything is obvious, even after thousands of hours contributing to the site, but I am not too old to learn. Regarding the answer *paraphrasing* other answers, I just wanted to underscore an aspect not addressed by other answers and non obvious for casual readers: `while (n-- > 0)` is perfect for `unsigned` types. – chqrlie Mar 12 '21 at 21:11
  • Fair enough. Perhaps a comment on an existing answer is more appropriate? – GManNickG Mar 12 '21 at 21:34
  • @GManNickG: I did comment about signed / unsigned differences on *GoodPerson*'s answer. My answer illustrates how this loop is simple and appropriate to enumerate array members. None of the answers address this either... let's see if other moderators see fit to delete it. – chqrlie Mar 12 '21 at 21:37