Cos'è l'operatore “->” in C ++?


8926

Dopo aver letto funzioni nascoste e angoli bui della C ++ / STL su comp.lang.c++.moderated, ero completamente sorpreso che il seguente frammento compilato e ha lavorato sia in Visual Studio 2008 e G ++ 4.4.

Ecco il codice:

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

Produzione:

9 8 7 6 5 4 3 2 1 0

Suppongo che questo sia C, dal momento che funziona anche in GCC. Da dove viene definito questo standard e da dove proviene?


503
O anche solo una spaziatura corretta ... Non credo di aver mai visto uno spazio tra la variabile e o ++o --prima ...
Matthew Scharley,

1154
Questo operatore "va a" può essere ripristinato (0 <- x). E c'è anche un operatore "corre verso" (0 <---- x). Accidenti, la cosa più divertente che abbia mai sentito parlare della sintassi c ++ =) +1 per la domanda.
SadSido,

233
Stranamente, sebbene l'interpretazione sia molto sbagliata, descrive ciò che il codice fa correttamente. :)
Noldorin,

811
Immagina le nuove possibilità di sintassi: #define upto ++<, #define downto -->. Se ti senti male, puoi fare #define for while(e #define do ) {(e #define done ;}) e scrivere for x downto 0 do printf("%d\n", x) doneOh, l'umanità ...
Chris Lutz

98
Apre la possibilità di un nuovo modo espressivo di codifica, vale la pena sacrificare alcuni avvisi del compilatore per: bool CheckNegative (int x) {return x <0? vero falso ); }
ttt,

Risposte:


8604

-->non è un operatore. Sono in effetti due operatori separati --e >.

Il codice del condizionale diminuisce x, restituendo xil valore originale (non decrementato), quindi confronta il valore originale con l' 0utilizzo >dell'operatore.

Per capire meglio, la dichiarazione potrebbe essere scritta come segue:

while( (x--) > 0 )

262
Poi di nuovo, sembra un tipo di operatore di gamma in quel contesto.
Charles Salvia,

109
Dire che x è post-decrementato e quindi confrontato con 0 equivale a dire che x è decrementato dopo essere stato confrontato con 0
Charles Salvia,

8
Non penso sia lo stesso. Penso che la parola "allora" implichi che esiste un ordine (dopo il decremento post, il valore di x è uno in meno). Penso che si possa dire "Stai post decrementando x e quindi confrontando il suo vecchio valore e 0 ..." per renderlo più chiaro. Ma questo è pignolo comunque. Sappiamo tutti cosa si intende.
Johannes Schaub - litb

38
In Java si compila anche :)
Steven Devijver,

44
Il suo nome, @Jay, è un cattivo stile di programmazione :-) Ciò è dimostrato dal fatto che la domanda è stata posta in primo luogo. Ha molto più senso legare testualmente gli operatori alla cosa su cui stanno operando piuttosto che qualcosa di non correlato, quindi while (x-- > 0)sarebbe più appropriato. Ciò rende anche più ovvio ciò che sta succedendo (almeno in un editor di caratteri fissi), il che significa che le parentesi in questa risposta non sarebbero necessarie.
paxdiablo,

3132

O per qualcosa di completamente diverso ... x diapositive 0.

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

Non così matematico, ma ... ogni immagine dipinge più di mille parole ...


216
@mafutrct - Come ricordo, \ in C aggiunge semplicemente la riga successiva come se non ci fosse un'interruzione di riga. Fondamentalmente qui non fanno nulla.
Hogan,

2
@mafu il carattere '\' dice al compilatore che la riga corrente continua nella riga successiva e quindi il compilatore dovrebbe unire entrambe le righe e compilarle come una sola. 'while (x -> 0)' verrà eseguito fino a quando x è uguale a -1. Ma il modo in cui fa le rientranze fa sembrare che x stia scivolando a zero. 'Mentre x scorre a 0 ...'
Felype,

16
IIRC, K&R C consentivano spazi bianchi tra le '-'s nell'operatore di decremento, nel qual caso si potevano avere le barre rovesciate al centro di esso, che sarebbero state ancora più fredde. :)
Jules il

10
@ArnavBorborah è un vecchio significato dell'espressione why waste words when a picture does a better job, usato come uno scherzo in questo contesto. (ci sono in realtà 2 parole chiave whilee printf)
non sincronizzato

88
Ah sì, l'oscuro operatore di diapositive. Come potrei dimenticare!
demonkoryu,


1278

È equivalente a

while (x-- > 0)

x--(post decremento) equivale a x = x-1così, il codice si trasforma in:

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

15
Questo non è del tutto giusto. Il valore di x all'interno del corpo del loop è diverso nel secondo caso. L'istruzione di assegnazione nel tuo esempio dovrebbe essere al di sopra della logica per essere equivalente. Postfix: sottrae 1, ma il confronto avverrà con il valore precedente alla sottrazione.
uliwitness

4
@uliwitness Questi sono veramente equivalenti. Sarebbe sbagliato se si usasse il prefisso: 0 >-- xin questo caso xviene decrementato prima della logica. In postfix, la logica viene eseguita prima del decremento e quindi entrambi i campioni sono equivalenti. Sentiti libero di scriverli in un Consolee testarli.
Candleshark,

12
Non sono ancora equivalenti. Dopo il primo ciclo, x è -1 (o overflow nel caso in cui sia senza segno), dopo il secondo, è 0. (Supponendo che x abbia inizio non negativo, nessuno dei due cicli modifica x o si rompe o ...)
Cesare

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

2
@Shebham, Ecco un contro esempio: se x inizia come 0, sotto il ciclo originale uscirà come -1, con la tua versione rimarrebbe zero. Quindi non sono equivalenti.
Elliott

1210

x può andare a zero ancora più velocemente nella direzione opposta:

int x = 10;

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

8 6 4 2

Puoi controllare la velocità con una freccia!

int x = 100;

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

90 80 70 60 50 40 30 20 10

;)


6
quale sistema operativo, questo tipo di output generato, sto usando Ubuntu 12.04 in quanto ho avuto un messaggio di errore
Bhuvanesh

74
Anche se dovrebbe essere ovvio, per tutti coloro che non conoscono C ++ leggendo questo: non farlo. Usa l'assegnazione aumentata se hai bisogno di incrementare / decrementare di più di uno.
Blimeo,

263
Zero con "laser". while (0> - - - - - - - - - - ---------- x) ... stessa uscita.
Samuel Danielson,

4
@phord sei sicuro che non si compili? -> coliru.stacked-crooked.com/a/5aa89a65e3a86c98
doc

18
@doc Si ​​compila in c ++, ma non in c.
phord

549

Suo

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

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

       printf("%d ", x);
     }

     return 0;
}

Solo lo spazio rende le cose divertenti, --diminuisce e >confronta.


432

L'uso di -->ha rilevanza storica. Il decremento era (e lo è ancora in alcuni casi), più veloce dell'incremento nell'architettura x86. L'uso -->suggerisce che xsta per farlo 0e fa appello a quelli con background matematici.


479
Non esattamente vero Il decremento e l'incremento richiedono la stessa quantità di tempo, il vantaggio di ciò è che il confronto con zero è molto veloce rispetto al confronto rispetto a una variabile. Questo è vero per molte architetture, non solo per x86. Qualsiasi cosa con un'istruzione JZ (salta se zero). Frugando in giro puoi trovare molti loop "for" scritti all'indietro per salvare cicli sul confronto. Questo è particolarmente veloce su x86 poiché l'atto di decrementare la variabile imposta il flag zero in modo appropriato, quindi puoi quindi diramare senza dover confrontare esplicitamente la variabile.
Burito,

25
Bene, il decremento verso zero significa che devi solo confrontare contro 0 per ogni iterazione, mentre iterare verso n significa confrontarti con n per ogni iterazione. Il primo tende ad essere più semplice (e su alcune architetture, viene automaticamente testato dopo ogni operazione di registrazione dei dati).
Joey Adams,

9
@burrito Anche se non sono in disaccordo, i loop condizionati su valori diversi da zero generalmente vengono previsti quasi perfettamente.
Duncan,

14
L'incremento e il decremento sono ugualmente veloci, probabilmente su tutte le piattaforme (sicuramente su x86). La differenza sta nel testare la condizione di fine del loop. Per vedere se il contatore ha raggiunto lo zero è praticamente libero - quando si decrementa un valore, viene impostato un flag zero nel processore e per rilevare la condizione finale è sufficiente controllare quel flag mentre quando si incrementa un'operazione di confronto è necessaria prima della condizione finale può essere rilevato.
lego,

7
Naturalmente, tutto ciò è discutibile in questi giorni, poiché i compilatori moderni possono vettorializzare e invertire i loop automaticamente.
Lambda Fairy,


363

Completamente geek, ma userò questo:

#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 - Sarebbe perfettamente geroglifico con parentesi egiziane
mouviciel

1
Questo non si compila. C non è Pascal, dove l'interno di do ... whileè un elenco di istruzioni. In C è un blocco, quindi deve essere do { ... } while.
Marchese di Lorne,

25
@EJP si compila. La sintassi è do statement while ( expression ) ;. Detto questo, spero che sia compreso, intendo l'esempio come uno scherzo.
Escualo,

321

Un libro che ho letto (non ricordo correttamente quale libro) affermava: i compilatori cercano di analizzare le espressioni con il token più grande usando la regola di destra a sinistra.

In questo caso, l'espressione:

x-->0

Analizza i token più grandi:

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

La stessa regola si applica a questa espressione:

a-----b

Dopo l'analisi:

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

Spero che questo aiuti a comprendere l'espressione complicata ^^


98
La tua seconda spiegazione non è corretta. Il compilatore vedrà a-----be penserà (a--)-- - b, che non viene compilato perché a--non restituisce un valore.
Tim Leaf,

22
Inoltre, xe --sono due gettoni separati.
Roland Illig,

23
@DoctorT: passa il lexer. solo il passaggio semantico è in grado di emettere quell'errore. quindi la sua spiegazione è corretta.
v.oddou,

9
Finché pensi che -->sia un operatore (che è ciò che implica la domanda che è stata posta), questa risposta non è affatto utile - penserai che il token 2 sia -->, non solo --. Se sai che -->non è un operatore, probabilmente non hai problemi a comprendere il codice nella domanda, quindi, a meno che tu non abbia una domanda completamente diversa, non sono davvero sicuro di come questo possa essere utile.
Bernhard Barker,

4
L'esempio @DoctorT può essere corretto supponendo che aabbia sovraccaricato l'operatore post-decremento, che restituisce lvalue. coliru.stacked-crooked.com/a/e1effc351ae79e9f
doc

275

Questo è esattamente lo stesso di

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

per numeri non negativi


153
Non dovrebbe essere for(--x++;--x;++x--)?
Mateen Ulhaq,

9
@DoctorT è quello che unsignedserve
Cole Johnson

12
@MateenUlhaq, che è sbagliato secondo lo standard, l'espressione --x++ha un comportamento indefinito secondo §1.9.15
WorldSEnder

Se lo avesse usato unsigned, avrebbe usato%u
Cacahuete Frito il

242

Ad ogni modo, ora abbiamo un operatore "va a". "-->"è facile essere ricordato come una direzione, e "mentre x va a zero" è significato-dritto.

Inoltre, è un po 'più efficiente rispetto "for (x = 10; x > 0; x --)"ad alcune piattaforme.


17
Non può essere vero sempre, specialmente quando il valore di x è negativo.
Ganesh Gopalasubramanian,

15
L'altra versione non fa la stessa cosa - con for (size_t x=10; x-->0; )il corpo del loop viene eseguito con 9,8, .., 0 mentre l'altra versione ha 10,9, .., 1. Altrimenti, è piuttosto complicato uscire da un ciclo a zero con una variabile non firmata.
Pete Kirkham,

4
Penso che questo sia un po 'fuorviante ... Non abbiamo un operatore letteralmente "va", dal momento che abbiamo bisogno di un altro ++>per fare il lavoro incrementale.
tslmy,

19
@Josh: in realtà, l'overflow dà un comportamento indefinito int, quindi potrebbe facilmente mangiare il tuo cane quanto xa zero se inizia negativo.
SamB,

3
Questo è un idioma molto importante per me per la ragione fornita nel comnmet da @PeteKirkham, poiché spesso ho bisogno di fare cicli decrescenti su quantità non firmate fino in fondo 0. (Per fare un confronto, l'idioma di omettere i test per zero, come scrivere while (n--)invece per non firmato n, non ti compra nulla e per me ostacola notevolmente la leggibilità.) Ha anche la piacevole proprietà di specificarne uno in più rispetto all'indice iniziale, che di solito è ciò che si desidera (ad esempio, per un loop su un array si specifica la sua dimensione). Mi piace anche -->senza spazio, in quanto ciò rende facile riconoscere il linguaggio.
Marc van Leeuwen,

221

Questo codice confronta prima x e 0 e quindi diminuisce x. (Detto anche nella prima risposta: stai post-decrementando x e quindi confrontando x e 0 con l' >operatore.) Vedi l'output di questo codice:

9 8 7 6 5 4 3 2 1 0

Ora confrontiamo prima e poi diminuiamo vedendo 0 nell'output.

Se vogliamo prima diminuire e poi confrontare, utilizzare questo codice:

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

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

Tale output è:

9 8 7 6 5 4 3 2 1

177

Il mio compilatore stamperà 9876543210 quando eseguo questo codice.

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

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

Come previsto. In while( x-- > 0 )realtà significa while( x > 0). Il x--post diminuisce x.

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

è un modo diverso di scrivere la stessa cosa.

È bello che l'originale assomigli "mentre x va a 0" però.


4
Il risultato è indefinito solo quando si incrementa / decrementa la stessa variabile più di una volta nella stessa istruzione. Non si applica a questa situazione.
Tim Leaf

13
while( x-- > 0 ) actually means while( x > 0)- Non sono sicuro di quello che stavi cercando di dire lì, ma il modo in cui lo hai formulato implica che --non ha alcun significato, il che è ovviamente molto sbagliato.
Bernhard Barker,

Per portare a casa il punto da @Dukeling, questa risposta non è la stessa del post originale. Nel post originale, xsarà -1dopo che lascia il ciclo, mentre in questa risposta, xsarà 0.
Mark Lakata,

148

Manca uno spazio tra --e >. xviene post decrementato, ovvero decrementato dopo aver verificato la condizione x>0 ?.


42
Lo spazio non manca - C (++) ignora gli spazi bianchi.

27
@ H2CO3 Questo non è vero in generale. Vi sono luoghi in cui è necessario utilizzare spazi bianchi per separare i token, ad es . #define foo()Rispetto a #define foo ().
Jens,

30
@Jens Che ne dici di: "Lo spazio non manca - C (++) ignora gli spazi bianchi non necessari."?
Kevin P. Rice,

139

--è l' operatore di decremento ed >è l' operatore maggiore di .

I due operatori vengono applicati come uno solo come -->.


11
Sono applicati come i 2 operatori separati che sono. Sono solo scritti in modo fuorviante per sembrare "uno solo".
underscore_d

129

È una combinazione di due operatori. Il primo --è per decrementare il valore, e >per verificare se il valore è maggiore dell'operando di destra.

#include<stdio.h>

int main()
{
    int x = 10;

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

    return 0;
}

L'output sarà:

9 8 7 6 5 4 3 2 1 0            

122

In realtà, xè post-decrementante e con quella condizione viene controllata. Non -->lo è(x--) > 0

Nota: il valore di xviene modificato dopo il controllo della condizione, poiché è in post-decremento. Alcuni casi simili possono anche verificarsi, ad esempio:

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

6
Solo che ++> difficilmente può essere usato in un po '(). Un operatore "va fino a ..." sarebbe ++ <, che non sembra affatto carino. L'operatore -> è una felice coincidenza.
Florian F,

2
@BenLeggiero Questo potrebbe 'funzionare' nel senso di generare codice che fa qualcosa (mentre fa infuriare i lettori a cui non piace il codice falso-intelligente), ma la semantica è diversa, poiché il suo uso del predecrement significa che eseguirà meno iterazioni. Come esempio forzato, non eseguirà mai il corpo del loop se xavviato a 1, ma lo while ( (x--) > 0 )farebbe. {edit} Eric Lippert ha trattato entrambe le note di rilascio di C # 4: blogs.msdn.microsoft.com/ericlippert/2010/04/01/…
underscore_d

120

C e C ++ obbediscono alla regola del "munch massimo". Allo stesso modo in cui a --- b viene tradotto (a--) - b, nel tuo caso si x-->0traduce in (x--)>0.

Ciò che la regola dice essenzialmente è che andando da sinistra a destra, le espressioni si formano prendendo il massimo dei caratteri che formeranno un'espressione valida.


5
Questo è ciò che l'OP ha assunto: che "((a) ->)" era il munch massimo. Si scopre che l'assunto originale del PO era errato: "->" non è un operatore valido massimo.
David,

4
Conosciuto anche come avido parsing, se ricordo bene.
Roy Tinker,

1
Scansione avida di @RoyTinker . Il parser non ha nulla a che fare con questo.
Marchese di Lorne,

27

Perché tutta la complicazione?

La semplice risposta alla domanda originale è solo:

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

Fa la stessa cosa. Non dire che dovresti farlo in questo modo, ma fa la stessa cosa e avrebbe risposto alla domanda in un post.

La x--è un sinonimo di quanto sopra, ed >è solo un normale maggiore di operator. Nessun grande mistero!

Ci sono troppe persone che complicano le cose semplici al giorno d'oggi;)


17
Questa domanda non riguarda le complicazioni, ma riguardo a ** Hidden Features and Dark Corners of C ++ / STL **
pix,

20
Il programma qui fornisce un output diverso rispetto all'originale perché x qui è decrementato dopo printf. Ciò dimostra bene come le "risposte semplici" siano in genere errate.
Öö 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, il

2
Non fa la stessa cosa. Sposta il tuo x=x-1prima printfquindi puoi dire "fa la stessa cosa".
CITBL,

26

In modo convenzionale definiremmo una condizione tra whileparentesi ad anello ()e una condizione di terminazione all'interno delle parentesi graffe {}, ma -->definiremo entrambe contemporaneamente.

Per esempio:

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

Questo diminuisce aed esegue il ciclo mentre aè maggiore di 0.

Convenzionalmente, sarebbe come:

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

In entrambi i modi, facciamo la stessa cosa e raggiungiamo gli stessi obiettivi.


5
Questo non è corretto Il codice nella domanda fa: 'test-write-execute' (prova prima, scrivi nuovo valore, esegui il ciclo), il tuo esempio è 'test-execute-write'.
v010dya,

@ v010dya Risolto il problema, ora è test-write-executecome nella domanda, grazie per averlo sottolineato!
Kotauskas,

@VladislavToncharov La tua modifica era ancora sbagliata. Vedi il mio
SS Anne,

8

(x --> 0) si intende (x-- > 0)

  1. Puoi usare (x -->)
    output -: 9 8 7 6 5 4 3 2 1 0

  2. puoi usare (-- x > 0) È cattivo(--x > 0)
    output -: 9 8 7 6 5 4 3 2 1

  3. Puoi usare
(--\
    \
     x > 0)

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

  1. Puoi usare
(\
  \
   x --> 0)

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

  1. Puoi usare
(\
  \
   x --> 0
          \
           \
            )

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

  1. puoi anche usare
(
 x 
  --> 
      0
       )

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

allo stesso modo, puoi provare molti metodi per eseguire correttamente questo comando

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.