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


8920

看完后隐藏的功能和C ++ / STL的暗角comp.lang.c++.moderated,我完全意外的是,下面的代码片断编译并在两个Visual Studio 2008和G ++ 4.4的工作。

这是代码:

#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,因为它也可以在GCC中使用。该标准在哪里定义,以及它来自何处?


502
甚至只是适当的间距...我认为我从来没有见过变量与之前++--之后的空格...
Matthew Scharley 09年

1154
可以还原此“转到”运算符(0 <-x)。并且还有一个“运行到”运算符(0 <---- x)。哎呀,这是我听过的最有趣的c ++语法=)+1。
SadSido

233
有趣的是,尽管解释很错误,但它确实描述了代码正确执行的操作。:)
Noldorin

810
想象一下新的语法可能性:#define upto ++<#define downto -->。如果您感到邪恶,则可以#define for while(#define do ) {(和#define done ;})一起写for x downto 0 do printf("%d\n", x) done哦,人性……
Chris Lutz

98
开启了一种全新的表达方式的可能性,值得牺牲一些编译器警告:bool CheckNegative(int x){return x <0?真假 ); }
ttt

Answers:


8594

-->不是运算符。实际上,这是两个单独的运算符,-->

有条件的代码递减x,同时返回x的原始值(未递减),然后0使用>运算符比较原始值。

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

while( (x--) > 0 )

262
再说一次,在那种情况下,它确实看起来像某种范围运算符。
查尔斯·萨尔维亚

109
说x递减然后与0进行比较就等于说x与0比较后即进行了递减
Charles Salvia

8
我认为不一样。我认为“然后”一词意味着存在一个顺序(在递减后,x的值要小一个)。我认为可以说“您先递减x,然后将其旧值与0 ...进行比较”,以使其更清晰。但这反正挑剔。我们都知道这是什么意思。
Johannes Schaub-litb 2010年

38
在Java中,它也会进行编译:)
Steven Devijver

44
它的名字@Jay是不好的编程风格:-)这首先要问这个问题,这证明了这一点。通过文本将运算符绑定到他们正在操作的对象上而不是无关的东西上会更有意义,因此while (x-- > 0)会更容易。这也使事情变得更加明显(至少在固定字体编辑器中),这意味着该答案中的括号将是不必要的。
paxdiablo '16

3129

或完全不同的东西... x滑到0

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

并不是那么数学,但是...每张画都画一千个单词...


216
@mafutrct-正如我记得的那样,\在C中只是追加了下一行,好像没有换行符一样。\ s在这里基本上什么也不做。
霍根2012年

2
@mafu的'\'字符告诉编译器当前行在下一行继续,因此编译器应合并两行并将其编译为一行。'while(x-> 0)'将一直运行,直到x等于-1。但是,他制作缩进的方式使x看起来像滑到了零。“虽然x滑到0 ...”
Felype 2013年

16
在IIRC中,K&R C允许在减量运算符中的“-”之间留有空格,在这种情况下,您可以在中间加上反斜杠,这样看起来会更酷。:)
Jules

10
@ArnavBorborah是一个古老的表达方式why waste words when a picture does a better job,在这种情况下用作玩笑。(实际上有2个关键字whileprintf
不同步的

87
啊,是的,晦涩的幻灯片操作员。我怎么会忘记!
demonkoryu


1277

相当于

while (x-- > 0)

x--(后减量)等价于此x = x-1,代码将转换为:

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

15
这不太正确。在第二种情况下,循环体内的x值不同。您的示例中的赋值语句应该在逻辑之上,以使其等效。后缀-减去1,但将与减法之前的值进行比较。
uliwitness

4
@uliwitness这些是真正等效的。如果使用前缀,那将是错误的:0 >-- x在这种情况下x,在逻辑之前递减。在后缀中,逻辑在减量之前执行,因此两个样本都是等效的。随意将它们编写为a Console并进行测试。
艾玛(Emma)

12
它们仍然不相等。在第一个循环之后,x为-1(或在无符号的情况下溢出),在第二个循环之后为0。(假设x开始为非负值,则两个循环都不会修改x或中断或...)
凯撒

1
while(x=x-1,x+1 > 0)是等效的。
SS安妮

2
@Shebham,这是一个反例:如果x以0开头,在原始循环下它将以-1退出,而对于您的版本,它将保持为零。因此它们不是等效的。
Elliott

1207

x 可以在相反的方向更快地达到零:

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

;)


6
哪种操作系统生成了这种类型的输出,我使用的是ubuntu 12.04,因为我有一条错误消息
Bhuvanesh 2015年

74
尽管这很明显,但是对于C ++新手来说,请阅读以下内容:不要这样做。如果您需要增加/减少一个以上,只需使用增值分配。
Blimeo

263
零与“激光”。while(0>-------------------- x)...相同的输出
塞缪尔·丹尼尔森,

4
@phord您确定它不会编译吗?-> coliru.stacked-crooked.com/a/5aa89a65e3a86c98
doc

18
@doc它在c ++中编译,但不在c中编译。
2014年

548

它的

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

     while( x-- > 0 ){ // x goes to 0

       printf("%d ", x);
     }

     return 0;
}

只是空间使事物看起来有趣,--减少和>比较。


431

的用法-->具有历史意义。减少(在某些情况下仍然是)比在x86架构上增加要快。使用-->建议x将适用于0,并吸引具有数学背景的人。


479
不完全正确。减量和增量花费相同的时间,这样做的好处是与变量比较相比,与零的比较非常快。这对于许多体系结构都是正确的,而不仅仅是x86。带有JZ指令的任何内容(如果为零则跳转)。随便看看,您会发现许多“ for”循环,这些循环被反向写入以节省比较周期。在x86上,这特别快,因为减少变量的操作会适当地设置零标志,因此您可以分支而不必显式比较变量。
burito

25
好吧,递减为零意味着您每次循环迭代仅需与0比较,而迭代n则意味着每次迭代均与n比较。前者往往更容易(在某些体系结构上,每次数据寄存器操作后都会自动进行测试)。
乔伊·亚当斯

9
@burrito尽管我不同意,但通常会预测以非零值为条件的循环接近完美。
Duncan 2014年

14
增量和减量同样快,可能在所有平台上(肯定在x86上)。区别在于测试循环结束条件。要查看计数器是否达到零几乎是免费的-当您递减一个值时,处理器中会设置一个零标志并检测结束条件,您只需要检查该标志即可;而当您递增一个值时,则需要在结束条件之前进行比较操作可以被检测到。
lego 2015年

7
当然,由于现代编译器可以自动向量化和逆向循环,因此如今这些都没有意义。
Lambda Fairy'2


362

极客,但我会用这个:

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

17
@SAFX-这将是带有埃及方括号的
mouviciel 2012年

1
这不会编译。C不是Pascal,其中的内部do ... while是语句列表。在C中,它是一个块,因此必须是do { ... } while
user207421'9

25
@EJP确实会编译。语法为do statement while ( expression ) ;。话虽如此,但我希望我理解这个例子是在开玩笑。
埃斯库洛

321

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

在这种情况下,表达式:

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

我希望这有助于理解复杂的表达方式^^


98
您的第二个解释不正确。编译器将看到a-----b并考虑(a--)-- - b,由于a--不返回左值,因此不会编译。
蒂姆·叶

22
此外,x--是两个单独的令牌。
罗兰·伊利格

23
@DoctorT:它通过词法分析器。只有语义传递才能够发出该错误。所以他的解释是正确的
v.oddou

9
只要您认为自己-->是一个运算符(这就是提出问题的隐含含义),那么这个答案根本就没有帮助-您会认为令牌2 -->不仅是--。如果您知道这-->不是运算符,那么您可能对理解问题中的代码没有任何疑问,因此,除非您有完全不同的问题,否则我不确定这将如何有用。
伯恩哈德·巴克

4
假设@DoctorT示例a具有重载的后减运算符(返回左值),则该示例是正确的。coliru.stacked-crooked.com/a/e1effc351ae79e9f
doc


242

无论如何,我们现在有一个“转到”运算符。"-->"容易被记住是一个方向,“ x变为零时”是直截了当的。

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


17
总是不能为真,特别是当x的值为负时。
2009年

15
另一个版本做不到相同的事情- for (size_t x=10; x-->0; )循环的主体以9,8,..,0执行,而另一个版本具有10,9,..,1。否则,使用无符号变量退出到零的循环是非常棘手的。
皮特·柯卡姆

4
我认为这有点误导...我们没有字面上的“去”运算符,因为我们需要另一个++>来执行增量工作。
tslmy13年

19
@Josh:实际上,溢出给带来了不确定的行为int,因此,x如果它开始为负值,就很容易像吃零狗一样吃掉你的狗。
SamB

3
由于@PeteKirkham在comnmet中给出的原因,这对我来说是一个非常重要的习惯用法,因为我经常需要一直减少对无符号数量的循环0。(为了进行比较,省略测试以零表示的习惯用法,例如while (n--)用无符号代替,这对n您来说什么也买不到,对我而言,这极大地妨碍了可读性。)它还具有令人愉悦的特性,即您指定的值比初始索引多一个,通常这就是您想要的(例如,对于数组的循环,请指定其大小)。我也喜欢-->没有空间,因为这使习语易于辨认。
Marc van Leeuwen 2014年

221

此代码首先将x与0进行比较,然后将x减1。(也请在第一个答案中说:先递减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

177

运行此代码时,我的编译器将打印出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”。


4
只有在同一条语句中多次增加/减少同一变量时,结果才是未定义的。它不适用于这种情况。
蒂姆·叶

13
while( x-- > 0 ) actually means while( x > 0)-我不确定您要在那说什么,但是您所说的方式暗含--任何含义,这显然是错误的。
伯恩哈德·巴克

为了推动从@Dukeling点回家,这答案是不一样的原职。在原始帖子中,x将在-1退出循环后返回,而在此答案中,x将返回0
Mark Lakata

148

--和之间缺少空格>x被递减,即在检查条件之后递减x>0 ?


42
不缺少空格-C(++)忽略空格。

27
@ H2CO3通常不是这样。在某些地方必须使用空格分隔标记,例如in #define foo()#define foo ()
詹斯

30
@Jens怎么样:“不缺少空格-C(++)忽略了不必要的空格。”?
凯文·赖斯

139

--减量运算符,>大于运算符。

这两个运算符像一样应用为一个-->


11
它们分别作为2个单独的运算符应用。他们只误导,看起来像“一单合一”。
underscore_d

129

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

#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            

122

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

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

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

6
除了++>几乎不能在while()中使用。“去...”运算符将是++ <,在任何地方看起来都不是很好。运算符->是一个巧合。
Florian F

2
@BenLeggiero从生成能够完成某些功能的代码的意义上说,这可以“起作用”(虽然激怒了不喜欢伪代码的读者),但是语义是不同的,因为使用predecreprence意味着它将执行更少的迭代。作为一个人为的示例,如果x从1开始,它将永远不会执行循环体,但是while ( (x--) > 0 )会执行。:{编辑}埃里克利珀在他的C#4发行说明既涉及blogs.msdn.microsoft.com/ericlippert/2010/04/01/...
underscore_d

120

CC ++遵循“最大嚼数”规则。将a --- b转换为的方式相同(a--) - b(在您的情况下,则 x-->0转换为)(x--)>0

规则本质上是说,从左到右,表达式是通过采用将构成有效表达式的最大字符组成的。


5
OP假设的是:“((a)->)”是最大的嚼口。事实证明,OP的原始假设是错误的:“->”不是最大有效运算符。
大卫

4
如果我没记错的话,也称为贪婪解析。
罗伊·廷克

1
@RoyTinker贪婪扫描。解析器与此无关。
user207421'9

27

为什么所有的并发症?

原始问题的简单答案是:

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

做同样的事情。并不是说您应该这样做,但是它做同样的事情,并且会在一篇文章中回答该问题。

x--是上述只是简写,并且>仅仅是一个正常大于operator。没什么大不了的!

如今有太多人使简单的事情变得复杂;)


17
这个问题不是关于复杂性,而是关于** C ++ / STL的隐藏功能和暗角**
pix

20
此处的程序输出的结果与原始结果不同,这是因为在printf之后x递减。这很好地说明了“简单答案”通常是不正确的。
二OO Tiib

2
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
安东尼

2
它不会做同样的事情。移动x=x-1之前,printf您可以说“它做同样的事情”。
CITBL

26

以常规方式,我们将在while循环括号中定义一个条件,()并在括号内定义一个终止条件{},但同时-->定义两者。

例如:

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

大于时,这会递减a并运行循环。a0

按照惯例,它将是:

int abc(void)
{
    int a = 5;
    while(a > 0)
    {
        a--;
        // Code
    }
    a--;
}

两种方式,我们都做相同的事情,实现相同的目标。


5
这是不正确的。问题中的代码会执行:“ test-write-execute”(先测试,然后写入新值,然后执行循环),您的示例为“ test-execute-write”。
v010dya

@ v010dya固定了答案,现在就test-write-execute在问题中,谢谢指出!
Kotauskas,

@VladislavToncharov您的编辑仍然错误。见我的。
SS安妮

8

(x --> 0) 手段 (x-- > 0)

  1. 您可以使用 (x -->)
    output -: 9 8 7 6 5 4 3 2 1 0

  2. 你可以用(-- x > 0) 它的意思(--x > 0)
    output -: 9 8 7 6 5 4 3 2 1

  3. 您可以使用
(--\
    \
     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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.