10168

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. I would assume this is also valid C since it works in GCC as well.

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

Where is this defined in the standard, and where has it come from?

3
  • 2
    The most dangerous feature of this construct is that it starts with 9 instead of 10. The same is true for for (int x = 10; x-->0;).
    – Sebastian
    Commented Apr 18 at 7:45
  • 1
    @Sebastian: yes, for (int x = 10; x --> 0;) starts at 9 and iterates down to 0 included. This is a feature, not necessarily intuitive for everyone, but very handy to enumerate entries in an array where the initial value of x is the length of the array: for (size_t i = sizeof(a) / sizeof(a[0]); i --> 0;) { /* do something with a[i] */ }
    – chqrlie
    Commented Apr 18 at 8:08
  • I think, it's vald in many languages which have postfix --. THis is 40 year-old running joke. Every 2-3 years there is a question about it XD Commented Apr 26 at 7:35

26 Answers 26

9849
+50

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

The code in the condition 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 )
4
  • 85
    I've seen it jokingly referred to as the "downto" operator (codegolf.stackexchange.com/questions/16226/…) Commented May 19, 2021 at 13:26
  • 15
    I think you wouldn't really need the parentheses around x-- though it does further enforce the separation. It would probably be enough just to associate tokens more clearly with something like while (x-- > 0).
    – paxdiablo
    Commented Jul 3, 2021 at 1:18
  • 5
    The most important reason to use this operator is I believe to avoid the "off-by-one" errors that occur when traversing an array in reverse It's quite easier to use for(int i = n; i-->0;) then for(int i = n-1; i >= 0; i--). Additionally, for unsigned the second for won't even work, and the first for is one of the easiest ways I've seen it written for unsigned.For example for(size_t i = n; i-->0;)
    – Vineet
    Commented Nov 8, 2022 at 21:16
  • @MosheBildner well, the more you look at it, IT IS the "downto operator".
    – user237419
    Commented Apr 18 at 6:58
3981

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...

0
2612

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.

0
1845

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

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

0
1468
+100

It's equivalent to

while (x-- > 0)

x-- (post decrement) is equivalent to x = x-1 (but returning the original value of x), so the code transforms to:

while(x > 0) {
    x = x-1;
    // logic
}
x--;   // The post decrement done when x <= 0
4
  • 25
    x-- is in no way equivalent to x = x-1. Commented Jan 24, 2022 at 17:22
  • 8
    They're semantically equivalent in this case Commented Apr 2, 2022 at 13:52
  • 3
    --x is equivalent to x = x-1 and x -=1. -1 from me.
    – Adola
    Commented May 4, 2022 at 5:38
  • 10
    You can say x-- is equivalent to (x = x-1) + 1.
    – Ofek
    Commented Nov 1, 2022 at 19:36
616

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.

504

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.

6
  • 577
    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
    Commented Dec 30, 2009 at 5:16
  • 44
    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
    Commented Apr 12, 2010 at 15:07
  • 13
    In x86 ASM, the LOOP <address> decreases the ECX register, then jumps to <address> 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. Commented Jul 8, 2015 at 11:26
  • 6
    Continuing my previous comment: MOV ECX, value, @start:, <code>, LOOP @start is an x86 ASM equivalent for counter = value - 1; while (counter --> 0) { <code>; }. Note that it will barf if value is initially zero, so an extra check is needed pre-loop. Commented Jul 8, 2015 at 11:32
  • 3
    LOOP was never particularly fast, though. Commented Apr 1, 2022 at 18:48
441

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;
}
3
  • 22
    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." Commented Mar 7, 2021 at 19:43
  • 4
    Calling atoi makes the code smell immediately. Commented Jan 24, 2022 at 17:24
  • 25
    @StevePoling Intent is being communicated. When I read this code, I understand that I am being trolled.
    – FriskySaga
    Commented Dec 8, 2022 at 20:06
378

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
0
303

This is exactly the same as while(x--) for non-negative numbers.

5
  • unless x is negative...
    – Geoduck
    Commented Nov 27, 2023 at 19:55
  • It really doesn't matter if x starts positive or negative, it will eventually reach zero.
    – jwdonahue
    Commented Jan 10 at 1:30
  • 1
    @jwdonahue it will cause undefined behaviour if x starts negative, due to signed integer overflow
    – M.M
    Commented Feb 2 at 3:19
  • @M.M I couldn't find that in my old C-11 draft. My recall may not be what it once was, but I am fairly sure that I have relied on integer decrement/increment wrapping around on more than one occasion in the past (DAC wave form generation). Haven't worked in C/C++ much these past 12 years though. Could you point us towards the standards language supporting your claim?
    – jwdonahue
    Commented Feb 2 at 4:38
  • 1
    @jwdonahue see stackoverflow.com/a/41280273/1505939 for Standard quotes
    – M.M
    Commented Feb 2 at 23:07
266

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.

11
  • 26
    Goes to cant be true always especially when value of x is negative. Commented Nov 13, 2009 at 3:22
  • 20
    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. Commented Jun 21, 2010 at 8:57
  • 9
    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
    Commented Jun 15, 2013 at 2:49
  • 26
    @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
    Commented Dec 6, 2013 at 6: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. Commented Aug 30, 2014 at 20:08
244

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
0
201

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.

3
  • 6
    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
    Commented May 5, 2010 at 15:30
  • 18
    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. Commented May 22, 2015 at 12:28
  • 2
    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. Commented Feb 24, 2020 at 16:41
169

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

3
  • 51
    The space is not missing - C(++) ignores whitespace.
    – user529758
    Commented Aug 2, 2012 at 19:16
  • 32
    @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
    Commented Apr 25, 2013 at 21:16
  • 35
    @Jens How about: "The space is not missing - C(++) ignores unnecessary white space."? Commented Dec 4, 2013 at 20:35
157

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

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

1
  • 19
    They're applied as the 2 separate operators they are. They're only written misleadingly to look like "a single one". Commented Nov 12, 2016 at 17:56
153

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            
148

C and C++ obey the "maximal 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 a valid token.

3
  • 7
    Which is what the OP assumed: that "((a)-->)" was the maximal munch. It turns out that the OP's original assumption was incorrect: "-->" is not a maximum valid operator.
    – david
    Commented Aug 28, 2014 at 0:41
  • 4
    Also known as greedy parsing, if I recall correctly.
    – Roy Tinker
    Commented Jul 11, 2015 at 1:04
  • 2
    @RoyTinker Greedy scanning. The parser has nothing to do with this.
    – user207421
    Commented Sep 11, 2016 at 2:21
138

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
2
  • 8
    Except that ++> can hardly be used in a while(). A "goes up to..." operator would be ++<, which doesn't look anywhere as nice. The operator --> is a happy coincidence.
    – Florian F
    Commented Sep 1, 2014 at 9: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: blogs.msdn.microsoft.com/ericlippert/2010/04/01/… Commented Nov 12, 2016 at 17:57
77

Instead of regular arrow operator (-->) you can use armor-piercing arrow operator: --x> (note those sharp barbs on the arrow tip). It adds +1 to armor piercing, so it finishes the loop 1 iteration faster than regular arrow operator. Try it yourself:

int x = 10;
while( --x> 0 )
    printf("%d ", x);
2
  • 14
    Don't forget about the Extra Long Arrow operator which moves twice as fast, x ----> 0 Commented Feb 24, 2022 at 2:58
  • 9
    and the Extra Long Armor Piercing Arrow operator, ----x> 0 for your fast piercing
    – cYee
    Commented Dec 8, 2022 at 15:26
37

The simple answer to the original question is that the following code does the same thing (though I am not saying you should do it like this):

#include <stdio.h>

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

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

5
  • 22
    This question is not about complications, but about ** Hidden Features and Dark Corners of C++/STL**
    – pix
    Commented Oct 27, 2016 at 15:32
  • 28
    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
    Commented May 13, 2017 at 9: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
    Commented Dec 15, 2017 at 18:33
  • 4
    It doesn't do the same thing. Move your x=x-1 before printf then you can say "it does the same thing".
    – CITBL
    Commented Jan 5, 2019 at 17:05
  • 1
    I agree with your attitude about simple and complicated, however x=x-1 is definitely more complicated than x-- (more characters to type, harder to read because people wonder why you're not just using good old x--, etc.) Also, C programmers who consider things like side effects in while to be overly complicated tend to make me suspicious. Commented Nov 17, 2021 at 11:06
34

(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.

34

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.

3
  • 6
    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
    Commented Jul 14, 2017 at 19:07
  • @S.S.Anne Your edit is still wrong. The a-- after the while shouldn't be there. Commented Dec 29, 2020 at 9: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
    Commented Mar 12, 2021 at 12:20
8

--> 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.

0
5

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.
1
  • You forgot to describe the -- at the end of the loop. Commented Jul 16, 2022 at 1:17
5

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.

0

That's what you mean.

while((x--) > 0)

We heard in childhood,

Stop don't, Let Go (روکو مت، جانے دو)

Where a Comma makes confusion

Stop, don't let go. (روکو، مت جانے دو)

Same Happens in Programming now, a SPACE makes confusion. :D

3
  • 1
    This idea can be abused for distant targets in a bow and arrow style: while((x --)> 0)
    – chqrlie
    Commented Jun 2, 2021 at 8:16
  • That's upto the understanding, whatever seems easy & understandable to a person, it's fine for him/her. Main Goal is to clear the concept and be a successful developer :) Commented Jun 2, 2021 at 8:21
  • Of course. And IMHO while (x --> 0) is clear and effective. x takes all values below the starting one down to and including 0, which is perfect for a loop enumerating index values for an array for both signed and unsigned types of x.
    – chqrlie
    Commented Jun 2, 2021 at 8:28

Not the answer you're looking for? Browse other questions tagged or ask your own question.