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?

GManNickG
fonte
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 )
Potatoswatter
fonte
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 ...

não sincronizados
fonte
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
2377

Esse é um operador muito complicado, portanto, mesmo o ISO / IEC JTC1 (Comitê Técnico Conjunto 1) colocou sua descrição em duas partes diferentes do Padrão C ++.

Brincadeiras à parte, eles são dois operadores diferentes: --e >descritos respectivamente nos §5.2.6 / 2 e §5.9 da Norma C ++ 03.

Kirill V. Lyadvinsky
fonte
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
Shubham
fonte
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

;)

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

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

Matt Joiner
fonte
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
366
while( x-- > 0 )

é assim que é analisado.

Grumdrig
fonte
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;
}
Arrieta
fonte
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 ^^

NguyenDat
fonte
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

Boa pessoa
fonte
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.

Teste
fonte
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
SjB
fonte
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".

cool_me5000
fonte
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 ?.

Mr. X
fonte
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 -->.

muntoo
fonte
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            
Rajeev Das
fonte
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
Android
fonte
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.

Peter Mortensen
fonte
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;)

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

Zohaib Ejaz
fonte
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

Kalana
fonte