O que é o operador "->" em C ++?


8925

Depois de ler características ocultas e Dark Corners de C ++ / STL on comp.lang.c++.moderated, I foi completamente surpreso que o seguinte trecho compilado e trabalhou em ambos os Visual Studio 2008 e G ++ 4.4.

Aqui está o código:

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

Resultado:

9 8 7 6 5 4 3 2 1 0

Eu diria que este é C, pois também funciona no GCC. De onde isso é definido no padrão e de onde veio?


503
Ou mesmo espaçamento apenas adequada ... eu não acho que eu já vi um espaço entre a variável e quer ++ou --antes ...
— Matthew Scharley

1154
Este operador "vai para" pode ser revertido (0 <- x). E também há um operador "corre para" (0 ​​<---- x). Nossa, a coisa mais engraçada que eu já ouvi sobre a sintaxe c ++ =) +1 para a pergunta.
— 30909 SadSido

233
Curiosamente, embora a interpretação esteja muito errada, ela descreve o que o código faz corretamente. :)
— Noldorin

811
Imagine as novas possibilidades de sintaxe: #define upto ++<, #define downto -->. Se você está se sentindo mal, você pode fazer #define for while(e #define do ) {(e #define done ;}) e escrever for x downto 0 do printf("%d\n", x) doneOh, a humanidade ...
— Chris Lutz

98
Abre a possibilidade de toda uma nova maneira expressiva de codificação, que vale a pena sacrificar alguns avisos do compilador para: bool CheckNegative (int x) {return x <0? verdadeiro falso ); }
— ttt

Respostas:


8603

-->não é um operador. Na verdade, são dois operadores separados, --e >.

O código da condicional diminui x, enquanto retorna xo valor original (não diminuído) e, em seguida, compara o valor original com o 0uso do >operador.

Para entender melhor, a declaração pode ser escrita da seguinte maneira:

while( (x--) > 0 )

262
Por outro lado, parece um tipo de operador de intervalo nesse contexto.
— 26630 Charles Salvia

109
Dizer que x é pós-diminuído e, em seguida, em comparação com 0 é o mesmo que dizer que x é reduzido depois de ser comparado a 0
— Charles Salvia

8
Eu não acho que é o mesmo. Eu acho que a palavra "então" implica que há uma ordem (após a diminuição do valor, o valor de x é um a menos). Acho que se pode dizer "Você está postando decrementando x e depois comparando seu valor antigo e 0 ..." para torná-lo mais claro. Mas isso é nitpicking de qualquer maneira. Todos sabemos o que se entende.
— Johannes Schaub - litb 30/01

38
Em Java também compila :)
— Steven Devijver

44
O nome, Jay, é um estilo de programação ruim :-) Isso é evidenciado pelo fato de a pergunta ter sido feita em primeiro lugar. Faz muito mais sentido vincular textualmente os operadores àquilo em que eles operam, em vez de algo não relacionado, por isso while (x-- > 0)seria mais adequado. Também torna mais óbvio o que está acontecendo (pelo menos em um editor de fonte fixa), significando que os parênteses nesta resposta não seriam necessários.
— paxdiablo

3131

Ou para algo completamente diferente ... xdesliza para 0.

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

Não é tão matemático, mas ... toda imagem pinta mil palavras ...


216
@ mafutrct - Pelo que me lembro \ em C apenas acrescenta a próxima linha como se não houvesse uma quebra de linha. Eles aqui basicamente não fazem nada.
— Hogan

2
@mafu o caractere '\' informa ao compilador que a linha atual continua na próxima linha e, portanto, o compilador deve mesclar as duas linhas e compilar como uma. 'while (x -> 0)' será executado até que x seja igual a -1. Mas, a maneira como ele faz os recuos faz parecer que x está deslizando para zero. 'Enquanto x desliza para 0 ...'
— Felype

16
O IIRC, K&R C permitiu um espaço em branco entre os '-'s no operador de decremento; nesse caso, você poderia ter as barras invertidas no meio dele, o que pareceria ainda mais legal. :)
— Jules

10
@ArnavBorborah é um significado antigo de expressão why waste words when a picture does a better job, usado como uma piada neste contexto. (na verdade, existem duas palavras while- chave e printf)
— não sincronizado

88
Ah, sim, o obscuro operador de slides. Como eu poderia esquecer!
— Demonkoryu 27/10/19


1277

É equivalente a

while (x-- > 0)

x--(pós-decremento) é equivalente a x = x-1, o código se transforma em:

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

15
Isso não está certo. O valor de x dentro do corpo do loop é diferente no segundo caso. A instrução de atribuição no seu exemplo deve estar acima da lógica para que seja equivalente. Postfix - subtrai 1, mas a comparação ocorrerá com o valor anterior à subtração.
— uliwitness

4
@uliwitness Estes são realmente equivalentes. Seria errado se o prefixo estivesse sendo usado: 0 >-- xneste caso, xé diminuído antes da lógica. No postfix, a lógica é executada antes do decremento e, portanto, as duas amostras são equivalentes. Sinta-se livre para escrevê-los em um Consolee testá-los.
— Candleshark

12
Eles ainda não são equivalentes. Após o primeiro loop, x é -1 (ou sobrevoa o caso de não ter sinal), após o segundo, é 0. (Assumindo que x começa não negativo, nenhum loop modifica x ou quebra ou…)
— César

1
while(x=x-1,x+1 > 0)é equivalente.
— SS Anne

2
@ Shebham, Aqui está um exemplo de contador: se x começa como 0, no loop original ele sairia como -1, com sua versão permaneceria zero. Portanto, eles não são equivalentes.
— Elliott

1209

x pode ir para zero ainda mais rápido na direção oposta:

int x = 10;

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

8 6 4 2

Você pode controlar a velocidade com uma flecha!

int x = 100;

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

90 80 70 60 50 40 30 20 10

;)


6
Qual sistema operacional, este tipo de saída gerada, eu estou usando um Ubuntu 12.04 em que eu tinha uma mensagem de erro
— Bhuvanesh

74
Embora deva ser óbvio, para todos os novatos em C ++ que estão lendo isso: não faça isso. Use a atribuição aumentada se precisar aumentar / diminuir em mais de um.
— Blimeo 26/03

263
Zero com "lasers". while (0> - - - - - - - - - ---------- x) ... mesma saída.
— Samuel Danielson

4
@phord tem certeza de que não compila? -> coliru.stacked-crooked.com/a/5aa89a65e3a86c98
— doc

18
@doc Compila em c ++, mas não em c.
— phord

548

Está

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

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

       printf("%d ", x);
     }

     return 0;
}

Apenas o espaço faz as coisas parecerem engraçadas, --diminui e >compara.


431

O uso de -->tem relevância histórica. Decrementar foi (e ainda é, em alguns casos), mais rápido que incrementar na arquitetura x86. Usar -->sugere que isso xvai 0e apela para aqueles com formação matemática.


479
Não é exatamente verdade. Decrementar e Incrementar levam a mesma quantidade de tempo, o benefício disso é que a comparação com zero é muito rápida em comparação à comparação com uma variável. Isso é verdade para muitas arquiteturas, não apenas para o x86. Qualquer coisa com uma instrução JZ (pule se zero). Ao bisbilhotar, você pode encontrar muitos loops "for" escritos para trás para economizar ciclos na comparação. Isso é particularmente rápido no x86, pois o ato de decrementar a variável define o sinalizador zero adequadamente, para que você possa ramificar sem precisar comparar explicitamente a variável.
— burito

25
Bem, decrementar para zero significa que você só precisa comparar com 0 por iteração de loop, enquanto iterar em direção a n significa comparar com n cada iteração. O primeiro tende a ser mais fácil (e em algumas arquiteturas, é testado automaticamente após cada operação de registro de dados).
— Joey Adams

9
@burrito Embora eu não discorde, os loops condicionados a valores diferentes de zero geralmente são previstos quase perfeitamente.
— Duncan

14
O incremento e o decremento são igualmente rápidos, provavelmente em todas as plataformas (definitivamente no x86). A diferença está no teste da condição final do loop. Para ver se o contador atingiu zero, é praticamente livre - quando você diminui um valor, um sinalizador zero é definido no processador e para detectar a condição final, basta verificar esse sinalizador, ao passo que quando você incrementa uma operação de comparação é necessária antes da condição final pode ser detectado.
— lego

7
Certamente, tudo isso é discutível atualmente, já que os compiladores modernos podem vetorizar e reverter loops automaticamente.
— fada Lambda


362

Totalmente nerd, mas vou usar isso:

#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 - seria perfeitamente hieróglifos com suportes egípcio
— mouviciel

1
Isso não compila. C não é Pascal, onde o interior de do ... whileé uma lista de instruções. Em C, é um bloco, por isso deve ser do { ... } while.
— Marquês de Lorne

25
@EJP compila. A sintaxe é do statement while ( expression ) ;. Dito isto, espero que entenda que eu quis dizer o exemplo como uma piada.
— Escualo 18/10/16

321

Um livro que li (não me lembro corretamente de qual livro) declarou: Os compiladores tentam analisar expressões para o maior token usando a regra esquerda direita.

Nesse caso, a expressão:

x-->0

Analisa os maiores tokens:

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

A mesma regra se aplica a esta expressão:

a-----b

Após a análise:

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

Espero que isso ajude a entender a expressão complicada ^^


98
Sua segunda explicação não está correta. O compilador verá a-----be pensará (a--)-- - b, o que não compila porque a--não retorna um lvalue.
— Tim Leaf

22
Além disso, xe --são dois sinais separados.
— Roland Illig

23
@ DoctorT: passa o lexer. somente o passe semântico é capaz de emitir esse erro. então a explicação dele está correta.
— precisa saber é o seguinte

9
Desde que você pense que -->é um operador (o que está implícito na pergunta), essa resposta não ajuda em nada - você pensará que o token 2 é -->, não apenas --. Se você sabe que -->não é um operador, provavelmente não tem problemas para entender o código da pergunta; portanto, a menos que tenha uma pergunta completamente diferente, não tenho muita certeza de como isso poderia ser útil.
— Bernhard Barker

4
O exemplo @DoctorT pode estar correto, assumindo que o aoperador pós- decréscimo foi sobrecarregado, o que retorna lvalue. coliru.stacked-crooked.com/a/e1effc351ae79e9f
— doc

275

É exatamente o mesmo que

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

para números não negativos


153
Isso não deveria ser for(--x++;--x;++x--)?
— Mateen Ulhaq 4/11/11

9
@DoctorT é isso que unsignedé para
— Cole Johnson

12
@MateenUlhaq, isso está errado de acordo com o padrão em que a expressão --x++tem um comportamento indefinido de acordo com §1.9.15
— WorldSEnder

Se ele estava usando unsigned, teria usado%u
— Cacahuete Frito

242

De qualquer forma, temos um operador "vai para" agora. "-->"é fácil ser lembrado como uma direção, e "enquanto x chega a zero" tem sentido direto.

Além disso, é um pouco mais eficiente do que "for (x = 10; x > 0; x --)"em algumas plataformas.


17
Não pode ser verdadeiro sempre, especialmente quando o valor de x é negativo.
— Ganesh Gopalasubramanian

15
A outra versão não faz a mesma coisa - com for (size_t x=10; x-->0; )o corpo do loop é executado com 9,8, .., 0 enquanto a outra versão tem 10,9, .., 1. É bastante complicado sair de um loop para zero com uma variável não assinada.
— Pete Kirkham

4
Eu acho que isso é um pouco enganador ... Não temos um operador literalmente "vai para", pois precisamos de outro ++>para fazer o trabalho incremental.
— tslmy

19
@ Josh: na verdade, o excesso fornece um comportamento indefinido int, portanto, ele poderia comer o seu cão com tanta facilidade quanto levar xa zero se começar negativo.
— SamB

3
Este é um idioma muito importante para mim, pelo motivo exposto no comnmet por @PeteKirkham, pois muitas vezes preciso fazer loops decrescentes sobre quantidades não assinadas até o fim 0. (Para comparação, o idioma de omitir testes para zero, como escrever while (n--)para não assinado n, não compra nada e para mim dificulta bastante a legibilidade.) Ele também possui a propriedade agradável de especificar um a mais que o índice inicial, que geralmente é o que você deseja (por exemplo, para um loop sobre uma matriz, você especifica seu tamanho). Também gosto -->sem espaço, pois isso facilita o reconhecimento do idioma.
— Marc van Leeuwen

221

Esse código primeiro compara x e 0 e depois diminui x. (Também foi dito na primeira resposta: você está decrescendo x e depois comparando x e 0 com o >operador.) Veja a saída deste código:

9 8 7 6 5 4 3 2 1 0

Agora, primeiro comparamos e depois diminuímos vendo 0 na saída.

Se quisermos primeiro diminuir e depois comparar, use este código:

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

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

Essa saída é:

9 8 7 6 5 4 3 2 1

177

Meu compilador imprimirá 9876543210 quando eu executar esse código.

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

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

Como esperado. O que while( x-- > 0 )realmente significa while( x > 0). A x--postagem diminui x.

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

é uma maneira diferente de escrever a mesma coisa.

É bom que o original pareça "enquanto x vai para 0".


4
O resultado é indefinido apenas quando você está incrementando / decrementando a mesma variável mais de uma vez na mesma instrução. Não se aplica a esta situação.
— Tim Leaf

13
while( x-- > 0 ) actually means while( x > 0)- Não sei ao certo o que você estava tentando dizer, mas a maneira como você expressou isso --não tem significado algum, o que obviamente está muito errado.
— Bernhard Barker

Para esclarecer o assunto a partir de @Dukeling, essa resposta não é a mesma da postagem original. No post original, xserá -1depois que sair do loop, enquanto nesta resposta xserá 0.
— Mark Lakata 24/02

148

Falta um espaço entre --e >. xé pós-decrementado, ou seja, diminuído após a verificação da condição x>0 ?.


42
O espaço não está faltando - C (++) ignora o espaço em branco.

27
@ H2CO3 Isso não é verdade em geral. Há lugares em que o espaço em branco deve ser usado para separar os tokens, por exemplo, em #define foo()versus #define foo ().
— Jens

30
@ Jens Que tal: "O espaço não está faltando - C (++) ignora espaços em branco desnecessários."?
— Kevin P. Arroz

139

--é o operador de decremento e >é o operador maior que .

Os dois operadores são aplicados como um único -->.


11
Eles são aplicados como os 2 operadores separados que são. Eles são escritos apenas de forma enganosa para parecer "um único".
— Sublinhado_d

129

É uma combinação de dois operadores. Primeiro, --é para diminuir o valor e >verificar se o valor é maior que o operando do lado direito.

#include<stdio.h>

int main()
{
    int x = 10;

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

    return 0;
}

A saída será:

9 8 7 6 5 4 3 2 1 0            

122

Na verdade, xé pós-decrementar e com essa condição está sendo verificada. Não é -->, é(x--) > 0

Nota: o valor de xé alterado após a condição ser verificada, porque é pós-decrescente. Alguns casos semelhantes também podem ocorrer, por exemplo:

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

6
Exceto que ++> dificilmente pode ser usado por um tempo (). Um operador "sobe para ..." seria ++ <, que não parece tão bom em nenhum lugar. O operador -> é uma feliz coincidência.
— Florian F

2
@BenLeggiero Isso poderia 'funcionar' no sentido de gerar código que faz alguma coisa (enquanto enfurece os leitores que não gostam de código falso-inteligente), mas a semântica é diferente, pois o uso de predileção significa que ele executará menos uma iteração. Como um exemplo artificial, ele nunca executaria o corpo do loop se xiniciado em 1, mas o while ( (x--) > 0 )faria. {edit} Eric Lippert abordou ambos em suas notas de versão do C # 4: blogs.msdn.microsoft.com/ericlippert/2010/04/01/…
— underscore_d

120

C e C ++ obedecem à regra "máxima mastigação". Da mesma forma que a --- b é traduzido para (a--) - b, no seu caso, é x-->0traduzido para (x--)>0.

O que a regra diz essencialmente é que, da esquerda para a direita, as expressões são formadas usando o máximo de caracteres que formarão uma expressão válida.


5
O que o OP assumiu: que "((a) ->)" era a máxima mastigação. Acontece que a suposição original do OP estava incorreta: "->" não é um operador válido máximo.
— david

4
Também conhecido como análise gananciosa, se bem me lembro.
— Roy Tinker

1
@RoyTinker Digitalização gananciosa . O analisador não tem nada a ver com isso.
— Marquês de Lorne

27

Por que toda a complicação?

A resposta simples para a pergunta original é apenas:

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

Faz a mesma coisa. Não estou dizendo que você deve fazer assim, mas faz a mesma coisa e teria respondido à pergunta em um post.

O x--é apenas uma abreviação para o acima exposto e >é apenas um normal maior que operator. Nenhum grande mistério!

Há muita gente complicando as coisas simples hoje em dia;)


17
Esta questão não é sobre complicações, mas sobre ** características ocultas e Dark Corners de C ++ / STL **
— pix

20
O programa aqui fornece uma saída diferente da original porque x aqui é decrementado após printf. Isso demonstra bem como "respostas simples" geralmente são incorretas.
— Öö Tiib

2
The OP's way: 9 8 7 6 5 4 3 2 1 0eThe Garry_G way: 10 9 8 7 6 5 4 3 2 1
— Anthony

2
Não faz a mesma coisa. Mova o seu x=x-1antes, printfentão você pode dizer "ele faz a mesma coisa".
— CITBL

26

Da maneira convencional, definiríamos uma condição entre whileparênteses do loop ()e uma condição de terminação dentro dos chavetas {}, mas -->definem as duas ao mesmo tempo.

Por exemplo:

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

Isso diminui ae executa o loop enquanto aé maior que 0.

Convencionalmente, seria como:

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

Nos dois sentidos, fazemos a mesma coisa e alcançamos os mesmos objetivos.


5
Isto está incorreto. O código da pergunta faz: 'test-write-execute' (teste primeiro, escreva novo valor, execute o loop), seu exemplo é 'test-execute-write'.
— v010dya

@ v010dya Corrigida a resposta, agora é test-write-executecomo na pergunta, obrigado por apontar!
— Kotauskas

@VladislavToncharov Sua edição ainda estava errada. Veja o meu.
— SS Anne

8

(x --> 0) significa (x-- > 0)

  1. você pode usar (x -->)
    output -: 9 8 7 6 5 4 3 2 1 0

  2. você pode usar (-- x > 0) é mau(--x > 0)
    output -: 9 8 7 6 5 4 3 2 1

  3. você pode usar
(--\
    \
     x > 0)

output -: 9 8 7 6 5 4 3 2 1

  1. você pode usar
(\
  \
   x --> 0)

output -: 9 8 7 6 5 4 3 2 1 0

  1. você pode usar
(\
  \
   x --> 0
          \
           \
            )

output -: 9 8 7 6 5 4 3 2 1 0

  1. você pode usar também
(
 x 
  --> 
      0
       )

output -: 9 8 7 6 5 4 3 2 1 0

Da mesma forma, você pode tentar vários métodos para executar este comando com sucesso

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.