C/C++中的“-->”运算符是什么?

What is the '-->' operator in C/C++?

提问人: 提问时间:10/29/2009 最后编辑:43 revs, 29 users 22%GManNickG 更新时间:11/2/2023 访问量:993077

问:

在阅读了 C++/STL 的隐藏功能和黑暗角落后,我完全惊讶于以下代码片段在 Visual Studio 2008 和 G++ 4.4 中编译和工作。我认为这也是有效的 C,因为它也适用于 GCC。comp.lang.c++.moderated

代码如下:

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

输出:

9 8 7 6 5 4 3 2 1 0

这在标准中定义在哪里,它从何而来?

C++ C 运算符 代码格式 标准 合规性

评论

1赞 Peter Mortensen 9/14/2023
一个带有笑话答案的笑话问题?植根于 Yashavant Kanetkar 的书
0赞 Peter Mortensen 9/14/2023
许多答案中突出显示的语法显然是不正确的。原因是什么?
0赞 chqrlie 9/14/2023
@PeterMortensen:不是真的:对于大多数人来说,这是一个真正的问题,他们惊讶地看到这个序列有多个冗余的答案,有些是严肃的,有些是有趣的......还有一个惊人的分数!-->

答:

9791赞 14 revs, 13 users 16%Bradley Mackey #1

-->不是运算符。它实际上是两个独立的运算符,并且 .-->

条件中的代码递减,同时返回 的原始(未递减)值,然后使用运算符将原始值进行比较。xx0>

为了更好地理解,该语句可以写成如下:

while( (x--) > 0 )

评论

77赞 Moshe Bildner 5/19/2021
我看到它被戏称为“下沉”运算符(codegolf.stackexchange.com/questions/16226/......)
14赞 paxdiablo 7/3/2021
我认为你真的不需要括号,尽管它确实进一步加强了分离。可能只要将令牌更清楚地与类似 .x--while (x-- > 0)
4赞 Vineet 11/9/2022
使用这个运算符的最重要原因是我相信可以避免反向遍历数组时发生的“off-by-one”错误 for(int i = n; i-->0;) then for(int i = n-1; i >= 0; i--)。此外,对于未签名,第二个 for 甚至不起作用,而第一个 for 是我见过的为 unsigned 编写的最简单方法之一。例如,for(size_t i = n; i-->0;)
1462赞 8 revs, 8 users 38%Shubham #2

它相当于

while (x-- > 0)

x--(后递减)等价于 (但返回 的原始值 ),因此代码转换为:x = x-1x

while(x > 0) {
    x = x-1;
    // logic
}
x--;   // The post decrement done when x <= 0

评论

21赞 Roland Illig 1/25/2022
x--绝不等同于 .x = x-1
8赞 Weston McNamara 4/2/2022
在这种情况下,它们在语义上是等价的
3赞 Adola 5/4/2022
--x等价于 和 。 从我这里。x = x-1x -=1-1
6赞 Ofek 11/2/2022
可以说相当于.x--(x = x-1) + 1
614赞 7 revs, 7 users 51%RageZ #3

#include <stdio.h>

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

只是空间让事情看起来很有趣,减少和比较。-->

2601赞 12 revs, 9 users 31%Kirill V. Lyadvinsky #4

这是一个非常复杂的运算符,因此即使是 ISO/IEC JTC1(联合技术委员会 1)也将其描述放在 C++ 标准的两个不同部分。

撇开玩笑不谈,它们是两个不同的运算符:分别在 C++03 标准的 §5.2.6/2 和 §5.9 中进行了描述。-->

265赞 4 revs, 3 users 56%Test #5

无论如何,我们现在有一个“去”运算符。 很容易被记住为一个方向,“而 X 归零”是意思直截了当的。"-->"

此外,它比某些平台更有效率。"for (x = 10; x > 0; x --)"

评论

26赞 Ganesh Gopalasubramanian 11/13/2009
总是不能为真,尤其是当 x 的值为负数时。
19赞 Pete Kirkham 6/21/2010
另一个版本不做同样的事情 - 循环主体以 9,8,..,0 执行,而另一个版本以 10,9,..,1 执行。否则,使用无符号变量退出循环到零是非常棘手的。for (size_t x=10; x-->0; )
9赞 tslmy 6/15/2013
我认为这有点误导......我们没有一个字面上的“goes to”运算符,因为我们需要另一个运算符来做增量工作。++>
25赞 SamB 12/6/2013
@Josh:实际上,溢出会给出未定义的行为,因此如果它开始为负值,它可以很容易地吃掉你的狗,就像把它带到零一样。intx
4赞 Marc van Leeuwen 8/31/2014
这对我来说是一个非常重要的成语,因为 @PeteKirkham 在 comnmet 中给出了原因,因为我经常需要对无符号数量一直到 .(相比之下,省略零测试的成语,例如写为无符号,对你一无所获,对我来说极大地阻碍了可读性。它还具有令人愉快的属性,即您比初始索引多指定一个,这通常是您想要的(例如,对于数组的循环,您可以指定其大小)。我也喜欢没有空格,因为这样可以使成语易于识别。0while (n--)n-->
500赞 Matt Joiner #6

的用法具有历史意义。在 x86 架构上,递减过去(在某些情况下仍然如此)比递增更快。使用暗示这将会,并吸引那些有数学背景的人。-->-->x0

评论

570赞 burito 12/30/2009
不完全正确。递减和递增需要相同的时间,这样做的好处是,与与变量的比较相比,与零的比较非常快。这适用于许多体系结构,而不仅仅是 x86。任何带有 JZ 指令的东西(如果为零则跳转)。四处逛逛,你会发现许多“for”循环是向后写的,以节省比较周期。这在 x86 上特别快,因为递减变量的行为会适当地设置零标志,因此您无需显式比较变量即可进行分支。
42赞 Joey Adams 4/12/2010
好吧,向零递减意味着你只需要在每次循环迭代中与 0 进行比较,而向 n 迭代意味着每次迭代都与 n 进行比较。前者往往更容易(在某些架构上,每次数据寄存器操作后都会自动测试)。
13赞 Mark K Cowan 7/8/2015
在 x86 ASM 中,递减寄存器,然后跳转到除非递减导致零。将循环计数器递减到零允许编译器生成单个指令,而递增或计数到其他值需要单独的 INC/DEC/ADD/SUB、COMPARE 和条件跳转指令。如果循环中未使用 的值,现代编译器通常可以将其他循环转换为循环。LOOP <address>ECX<address>ECXLOOPcounter --> 0counter
6赞 Mark K Cowan 7/8/2015
继续我之前的评论:, , , 是 的 x86 ASM 等效项。请注意,如果初始为零,它将 barf,因此需要在循环前进行额外的检查。MOV ECX, value@start:<code>LOOP @startcounter = value - 1; while (counter --> 0) { <code>; }value
2赞 Remember Monica 4/2/2022
不过,LOOP从来都不是特别快。
243赞 5 revs, 4 users 70%SjB #7

此代码首先比较 x 和 0,然后递减 x.(在第一个答案中也说过:您正在递减 x,然后将 x 和 0 与运算符进行比较。请参阅以下代码的输出:>

9 8 7 6 5 4 3 2 1 0

现在,我们首先进行比较,然后通过在输出中看到 0 来递减。

如果我们想先递减再比较,请使用以下代码:

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

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

该输出为:

9 8 7 6 5 4 3 2 1
168赞 2 revs, 2 users 50%Mr. X #8

和 之间缺少空格。 是后递减的,即检查条件后递减。-->xx>0 ?

评论

50赞 8/3/2012
空格不丢失 - C(++) 忽略空格。
31赞 Jens 4/26/2013
@H2CO3 一般来说,情况并非如此。有些地方必须使用空格来分隔标记,例如 in versus .#define foo()#define foo ()
34赞 Kevin P. Rice 12/5/2013
@Jens 怎么样:“空格没有丢失 - C(++) 忽略不必要的空格。
301赞 5 revs, 4 users 42%Jan Schultke #9

假设在循环之前为正,则等价于:xwhile (x --> 0)

while (x--)

评论

0赞 Garr Godfrey 11/28/2023
除非 x 是负数...
200赞 5 revs, 4 users 82%cool_me5000 #10

当我运行此代码时,我的编译器将打印出9876543210。

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

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

不出所料。实际的意思是.帖子递减。while( x-- > 0 )while( x > 0)x--x

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

是写同一件事的不同方式。

不过,原版看起来像“当 x 变为 0”时,这很好。

评论

6赞 Tim Leaf 5/5/2010
仅当您在同一语句中多次递增/递减同一变量时,结果才未定义。它不适用于这种情况。
18赞 Bernhard Barker 5/22/2015
while( x-- > 0 ) actually means while( x > 0)- 我不确定你想在那里说什么,但你表达的方式暗示没有任何意义,这显然是非常错误的。--
2赞 Mark Lakata 2/25/2020
为了从@Dukeling中说明这一点,这个答案与原始帖子不同。在原来的帖子中,将在它离开循环之后,而在这个答案中,将是.x-1x0
156赞 4 revs, 4 users 38%muntoo #11

--递减运算符,并且是大于运算符。>

这两个运算符作为单个运算符应用,如 。-->

评论

19赞 underscore_d 11/13/2016
它们作为 2 个独立的运算符应用。它们只是写得具有误导性,看起来像“一个”。
375赞 7 revs, 6 users 54%NguyenDat #12

我读过的一本书(我记不清是哪本书)说:编译器尝试使用左右规则将表达式解析为最大的标记

在本例中,表达式:

x-->0

解析为最大的令牌:

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

同样的规则也适用于这个表达式:

a-----b

解析后:

token 1: a
token 2: --
token 3: --
token 4: -
token 5: b
conclude: (a--)-- - b
436赞 3 revs, 2 users 76%Arrieta #13

完全是极客,但我会用这个:

#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;
}

评论

21赞 StevePoling 3/8/2021
我知道它看起来很酷,但我担心它具有欺骗性。你写C++而不是机器语言的原因是,你想把你的意图传达给下一个阅读你的代码的人。这种构造违反了最小意外原则。这是一种精神上的“绊倒危险”。
4赞 Roland Illig 1/25/2022
调用会立即使代码闻起来。atoi
17赞 FriskySaga 12/9/2022
@StevePoling 正在传达意向。当我阅读这段代码时,我明白我正在被拖钓。
3922赞 8 revs, 8 users 60%unsynchronized #14

或者对于完全不同的东西...... 滑动到 .x0

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

不是那么数学,但是......每张图片都描绘了千言万语......

136赞 3 revs, 3 users 70%AndroidLearner #15

实际上,正在减少,并且正在检查这种情况。不是,而是x-->(x--) > 0

注意:值在检查条件后更改,因为它在递减后。一些类似的情况也可能发生,例如:x

-->    x-->0
++>    x++>0
-->=   x-->=0
++>=   x++>=0

评论

8赞 Florian F 9/1/2014
除了 ++> 在一段时间内几乎不能使用()。一个“上升到......”运算符将是 ++<,这看起来并不那么好。运算符 --> 是一个令人高兴的巧合。
2赞 underscore_d 11/13/2016
@BenLeggiero 在生成执行某些操作的代码的意义上,这可以“工作”(同时激怒不喜欢虚假代码的读者),但语义不同,因为它使用predecrement意味着它将执行更少的迭代。作为一个人为的例子,如果从 1 开始,它永远不会执行循环体,但会执行。{编辑}Eric Lippert 在他的 C# 4 发行说明中介绍了这两者:blogs.msdn.microsoft.com/ericlippert/2010/04/01/...xwhile ( (x--) > 0 )
148赞 4 revs, 4 users 56%Rajeev Das #16

它是两个运算符的组合。首先是递减值,用于检查值是否大于右操作数。-->

#include<stdio.h>

int main()
{
    int x = 10;

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

    return 0;
}

输出将是:

9 8 7 6 5 4 3 2 1 0            
147赞 4 revs, 3 users 33%Peter Mortensen #17

C 和 C++ 遵循“最大咀嚼”规则。同样的方式被翻译成 ,在你的例子中翻译成 。a---b(a--) - bx-->0(x--)>0

该规则本质上是从左到右,表达式是通过获取将形成有效令牌的最大字符来形成的。

评论

6赞 david 8/28/2014
这就是OP的假设:“((a)-->)”是最大的咀嚼。事实证明,OP 最初的假设是不正确的:“-->”不是最大有效运算符。
4赞 Roy Tinker 7/11/2015
如果我没记错的话,也称为贪婪解析。
2赞 user207421 9/11/2016
@RoyTinker贪婪扫描。解析器与此无关。
1800赞 6 revs, 4 users 91%mip #18

x在 C++ 中,可以在相反的方向上更快地归零:

int x = 10;

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

8 6 4 2

你可以用箭头控制速度!

int x = 100;

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

90 80 70 60 50 40 30 20 10

;)

评论

2赞 Roland Illig 1/25/2022
错误:需要 lvalue 作为递减操作数
14赞 Sergey Barannikov 7/15/2022
@RolandIllig 它仅在 C++ 中受支持,在 C 中不受支持。
1赞 Roland Illig 7/16/2022
@SergeyBarannikov谢谢,我更新了答案以反映您的评论
36赞 6 revs, 5 users 58%Garry_G #19

原始问题的简单答案是以下代码执行相同的操作(尽管我并不是说您应该这样做):

#include <stdio.h>

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

这只是上述内容的简写,只是一个正常的大于 。x-->operator

评论

22赞 pix 10/27/2016
这个问题不是关于复杂性,而是关于 C++/STL 的隐藏功能和黑暗角落**
28赞 Öö Tiib 5/13/2017
这里的程序给出的输出与原始程序不同,因为这里的 x 在 printf 之后递减。这很好地说明了“简单的答案”通常是不正确的。
3赞 Anthony 12/16/2017
The OP's way: 9 8 7 6 5 4 3 2 1 0The Garry_G way: 10 9 8 7 6 5 4 3 2 1
4赞 CITBL 1/6/2019
它不会做同样的事情。移动你的之前,你可以说“它做同样的事情”。x=x-1printf
1赞 Wolfram Rösler 11/17/2021
我同意你对简单和复杂的态度,但是肯定比(要输入的字符更多,更难阅读,因为人们想知道为什么你不只是使用旧的等)更复杂。此外,那些认为副作用之类的事情过于复杂的 C 程序员往往会让我产生怀疑。x=x-1x--x--while
33赞 4 revs, 4 users 56%Zohaib Ejaz #20

我们用传统的方式在while循环括号中定义条件,并在大括号内定义终止条件“”,但这是一种一次性定义的方式。 例如:(){}-->

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

它说,递减并运行循环,直到时间大于aa0

其他方式应该是这样的:

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

无论哪种方式,我们都做同样的事情,实现相同的目标。

评论

6赞 v010dya 7/15/2017
这是不正确的。问题中的代码是:“test-write-execute”(首先测试,写入新值,执行循环),您的示例是“test-execute-write”。
0赞 Stefan Fabian 12/29/2020
@S.S.Anne 您的编辑仍然错误。之后的时间不应该在那里。a--
0赞 chqrlie 3/12/2021
无论哪种方式,我们都做同样的事情,实现相同的目标。并非如此:两个循环都迭代了 5 次,但循环完成后的最终值是第一种情况和第二种情况。a-10
31赞 2 revs, 2 users 87%Kalana #21

(x --> 0)方法。(x-- > 0)

  1. 你可以使用(x -->)
    Output: 9 8 7 6 5 4 3 2 1 0
  1. 你可以使用 It's mean(-- x > 0)(--x > 0)
    Output: 9 8 7 6 5 4 3 2 1
  1. 你可以使用
(--\
    \
     x > 0)

Output: 9 8 7 6 5 4 3 2 1

  1. 你可以使用
(\
  \
   x --> 0)

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

  1. 你可以使用
(\
  \
   x --> 0
          \
           \
            )

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

  1. 您还可以使用
(
 x 
  --> 
      0
       )

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

同样,您可以尝试多种方法来成功执行此命令。

5赞 2 revs, 2 users 60%Peter Mortensen #22

这根本不是运算符。我们有一个像 ,但不是 的运算符。这只是一个错误的解释,它只是意味着 x 具有后递减运算符,并且此循环将运行直到它大于-->->-->while(x-- >0)

编写此代码的另一种简单方法是 .while 循环将在获得错误条件时停止,这里只有一种情况,即 .因此,当 x 值递减到时,它将停止。while(x--)0

5赞 2 revs, 2 users 74%Neeraj Bansal #23

这是一元后递减运算符。--

 while (x-- > 0) // x goes to 0
 {
     printf("%d ", x);
 }
  • 一开始,条件将评估为(x > 0) // 10 > 0
  • 现在,由于条件为真,它将以递减的值进入循环x-- // x = 9
  • 这就是为什么第一个打印值是 9 的原因
  • 等等。在最后一个循环中,所以条件为真。根据一元运算符,该值更改为打印时的值。x=1x = 0
  • 现在,,它将条件评估为 false,while 循环退出。x = 0(x > 0 )

评论

0赞 Roland Illig 7/16/2022
你忘了描述循环结束时的。--
7赞 2 revschqrlie #24

-->不是运算符,它是 (post-decrement) 和 (greater than comparison) 的并列。-->

循环看起来更熟悉,如下所示:

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

此循环是一个经典的习惯用语,用于枚举(排除的上限)和包含的下限之间的值,可用于从最后一个到第一个遍历数组的元素。100

初始值是迭代总数(例如数组的长度),1 加上循环中使用的第一个值。是循环内部的最后一个值,因此注释 x 变为 0100x

请注意,循环完成后的值为 。x-1

另请注意,如果具有无符号类型(例如 ),则此循环将以相同的方式运行,这与朴素替代方案相比具有很大的优势。xsize_tfor (i = length-1; i >= 0; i--)

出于这个原因,我实际上是这个令人惊讶的语法的粉丝:.我发现这个成语既醒目又优雅,就像 vs: 一样(看起来令人困惑地类似于 )。它也适用于其他语言,其语法受C启发:C++,Objective-C,java,javascript,C#等等。while (x --> 0)for (;;)while (1)while (l)

0赞 Numan Gillani #25

这就是你的意思。

while((x--) > 0)

我们在童年时就听说过,

停止不要,放手 (روکو مت، جانے دو)

逗号造成混淆的地方

停下来,不要放手。(روکو، مت جانے دو)

现在在编程中也会发生同样的情况,空格会造成混乱。:D

评论

0赞 chqrlie 6/2/2021
这个想法可以被滥用于弓箭风格的远处目标:while((x --)> 0)
0赞 Numan Gillani 6/2/2021
这取决于理解,无论对一个人来说似乎容易和理解什么,对他/她来说都很好。主要目标是清除概念并成为一名成功的开发人员:)
0赞 chqrlie 6/2/2021
答案是肯定的。恕我直言,清晰有效。 将起始值以下的所有值包括 ,这非常适合枚举有符号和无符号类型数组的索引值的循环。while (x --> 0)x0x
71赞 2 revs, 2 users 67%hydrechan #26

您可以使用穿甲箭头运算符 (-->) 代替常规的箭头运算符:--x>(注意箭头尖端的锋利倒钩)。它为穿甲增加了 +1,因此它比普通箭头操作员更快地完成循环 1 迭代。自己试一试:

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

评论

11赞 Albert Renshaw 2/24/2022
别忘了移动速度快两倍的操作员,Extra Long Arrowx ----> 0
7赞 cYee 12/8/2022
和操作员,为您的快速穿孔Extra Long Armor Piercing Arrow----x> 0