¿Cuál es el operador "->" en C ++?

8926

Después de leer las características ocultas y oscuras esquinas de C ++ / STL sobre comp.lang.c++.moderated, me sorprendió por completo que el siguiente fragmento compila y se trabajó tanto en Visual Studio 2008 y G ++ 4.4.

Aquí está el código:

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

Salida:

9 8 7 6 5 4 3 2 1 0

Supongo que esto es C, ya que también funciona en GCC. ¿Dónde se define esto en el estándar y de dónde viene?

GManNickG
fuente
503
O incluso simplemente el espaciamiento adecuado ... no creo que he visto nunca un espacio entre la variable y, o bien ++o --antes ...
Mateo Scharley
1154
Este operador "va a" se puede revertir (0 <- x). Y también hay un operador "corre a" (0 ​​<---- x). Dios, la cosa más divertida que he escuchado sobre la sintaxis de c ++ =) +1 para la pregunta.
SadSido
233
Curiosamente, aunque la interpretación es muy incorrecta, describe lo que el código hace correctamente. :)
Noldorin
811
Imagine las nuevas posibilidades de sintaxis: #define upto ++<, #define downto -->. Si te sientes malvado, puedes hacerlo #define for while(y #define do ) {(y #define done ;}) y escribir for x downto 0 do printf("%d\n", x) doneOh, la humanidad ...
Chris Lutz
98
Abre la posibilidad de una nueva forma expresiva de codificación, vale la pena sacrificar algunas advertencias del compilador por: bool CheckNegative (int x) {return x <0? verdadero Falso ); }
ttt

Respuestas:

8604

-->No es un operador. De hecho, son dos operadores separados, --y >.

El código del condicional disminuye x, mientras devuelve xel valor original (no disminuido) y luego compara el valor original con el 0uso del >operador.

Para comprender mejor, la declaración podría escribirse de la siguiente manera:

while( (x--) > 0 )
Potatoswatter
fuente
262
Por otra parte, se parece a algún tipo de operador de rango en ese contexto.
Charles Salvia
109
Decir que x es decrementado posteriormente y luego comparado con 0 es lo mismo que decir que x es decrementado después de ser comparado con 0
Charles Salvia
8
No creo que sea lo mismo. Creo que la palabra "entonces" implica que hay un orden (después de la disminución, el valor de x es uno menos). Creo que uno puede decir "Estás decrementando x y luego comparando su valor anterior y 0 ..." para hacerlo más claro. Pero esto es una trampa de todos modos. Todos sabemos lo que significa.
Johannes Schaub - litb
38
En Java también compila :)
Steven Devijver
44
Su nombre, @Jay, es un mal estilo de programación :-) Esto se evidencia por el hecho de que la pregunta se hizo en primer lugar. Tiene mucho más sentido vincular textualmente a los operadores a lo que están operando en lugar de algo no relacionado, por while (x-- > 0)lo que sería más adecuado. También hace más obvio lo que está sucediendo (al menos en un editor de fuentes fijas), lo que significa que los paréntesis en esta respuesta no serían necesarios.
paxdiablo
3132

O para algo completamente diferente ... se xdesliza a 0.

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

No es tan matemático, pero ... cada imagen vale más que mil palabras ...

no sincronizado
fuente
216
@mafutrct: como lo recuerdo, \ en C solo agrega la siguiente línea como si no hubiera un salto de línea. Aquí básicamente no hacemos nada.
Hogan
2
@mafu, el carácter '\' le dice al compilador que la línea actual continúa en la siguiente línea, por lo que el compilador debe fusionar ambas líneas y compilar como una sola. 'while (x -> 0)' se ejecutará hasta que x sea igual a -1. Pero, la forma en que hace las muescas hace que parezca que x se desliza a cero. 'Mientras x se desliza a 0 ...'
Felype
16
IIRC, K&R C permitieron espacios en blanco entre los '-'s en el operador de decremento, en cuyo caso podría tener las barras invertidas en el medio, lo que se vería aún más fresco. :)
Julio
10
@ArnavBorborah es un antiguo significado de expresión why waste words when a picture does a better job, utilizado como una broma en este contexto. (de hecho, hay 2 palabras clave whiley printf)
no sincronizado
88
Ah sí, el oscuro operador de diapositivas. ¡Como podría olvidarlo!
demonkoryu
2378

Es un operador muy complicado, por lo que incluso ISO / IEC JTC1 (Comité Técnico Conjunto 1) colocó su descripción en dos partes diferentes del Estándar C ++.

Bromas aparte, son dos operadores diferentes: --y se >describen respectivamente en §5.2.6 / 2 y §5.9 del Estándar C ++ 03.

Kirill V. Lyadvinsky
fuente
1278

Es equivalente a

while (x-- > 0)

x--(disminución posterior) es equivalente a x = x-1esto, el código se transforma en:

while(x > 0) {
    x = x-1;
    // logic
}
x--;   // The post decrement done when x <= 0
Shubham
fuente
15
Esto no está del todo bien. El valor de x dentro del cuerpo del bucle es diferente en el segundo caso. La declaración de asignación en su ejemplo debe estar por encima de la lógica para que sea equivalente. Postfix: resta 1, pero la comparación se realizará con el valor anterior a la resta.
uliwitness
44
@uliwitness Estos son realmente equivalentes. Sería incorrecto si se usara el prefijo: 0 >-- xen este caso xse disminuye antes de la lógica. En postfix, la lógica se ejecuta antes de la disminución y, por lo tanto, ambas muestras son equivalentes. Siéntase libre de escribirlos en un Consoley probarlos.
Candleshark el
12
Todavía no son equivalentes. Después del primer bucle, x es -1 (o se desborda en caso de que no esté firmado), después del segundo, es 0. (Suponiendo que x comienza no negativo, ninguno de los bucles modifica x o se rompe o ...)
César
1
while(x=x-1,x+1 > 0)es equivalente.
SS Anne
2
@Shebham, aquí hay un ejemplo de contador: si x comienza como 0, bajo el bucle original saldría como -1, con su versión permanecería cero. Entonces no son equivalentes.
Elliott
1210

x puede ir a cero aún más rápido en la dirección opuesta:

int x = 10;

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

8 6 4 2

¡Puedes controlar la velocidad con una flecha!

int x = 100;

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

90 80 70 60 50 40 30 20 10

;)

doc.
fuente
66
qué sistema operativo, este tipo de salida generado, estoy usando un ubuntu 12.04 porque tenía un mensaje de error
Bhuvanesh
74
Aunque debería ser obvio, para todos los nuevos en C ++ que lean esto: no lo hagas. Simplemente use la asignación aumentada si necesita aumentar / disminuir en más de uno.
Blimeo
263
Cero con "láseres". while (0> - - - - - - - - - - ---------- x) ... misma salida.
Samuel Danielson
44
@phord, ¿estás seguro de que no se compila? -> coliru.stacked-crooked.com/a/5aa89a65e3a86c98
doc
18
@doc Se compila en c ++, pero no en c.
Phord
549

Sus

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

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

       printf("%d ", x);
     }

     return 0;
}

Solo el espacio hace que las cosas se vean divertidas, --decrecientes y >comparables.

RageZ
fuente
432

El uso de -->tiene relevancia histórica. Disminuir fue (y sigue siendo en algunos casos), más rápido que incrementar en la arquitectura x86. El uso -->sugiere que eso xva a ser 0y atrae a aquellos con antecedentes matemáticos.

Matt Joiner
fuente
479
No es exactamente cierto. La disminución y el aumento toman la misma cantidad de tiempo, el beneficio de esto es que la comparación con cero es muy rápida en comparación con la comparación con una variable. Esto es cierto para muchas arquitecturas, no solo x86. Cualquier cosa con una instrucción JZ (saltar si es cero). Escudriñando puede encontrar muchos bucles "for" que están escritos al revés para guardar ciclos en la comparación. Esto es particularmente rápido en x86, ya que el acto de disminuir la variable establece el indicador de cero de manera apropiada, por lo que podría ramificarse sin tener que comparar explícitamente la variable.
burito
25
Bueno, disminuir hacia cero significa que solo tiene que comparar con 0 por iteración de bucle, mientras que iterar hacia n significa comparar con n cada iteración. El primero tiende a ser más fácil (y en algunas arquitecturas, se prueba automáticamente después de cada operación de registro de datos).
Joey Adams
99
@burrito Aunque no estoy en desacuerdo, los bucles condicionados a valores distintos de cero generalmente se predicen casi a la perfección.
Duncan
14
El incremento y la disminución son igualmente rápidos, probablemente en todas las plataformas (definitivamente en x86). La diferencia está en probar la condición final del bucle. Para ver si el contador ha llegado a cero es prácticamente libre: cuando disminuye un valor, se establece un indicador de cero en el procesador y para detectar la condición final solo necesita verificar ese indicador, mientras que cuando se incrementa una operación de comparación es necesaria antes de la condición final puede ser detectado
lego
77
Por supuesto, todo esto es discutible en estos días, ya que los compiladores modernos pueden vectorizar y revertir bucles automáticamente.
Lambda Fairy
367
while( x-- > 0 )

es cómo se analiza eso.

Grumdrig
fuente
363

Completamente geek, pero usaré esto:

#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
fuente
17
@SAFX - Sería perfectamente jeroglíficos con paréntesis
egipcios
1
Esto no se compila. C no es Pascal, donde el interior de do ... whilees una lista de declaraciones. En C es un bloque, por lo que debe ser do { ... } while.
Marqués de Lorne
25
@EJP sí compila. La sintaxis es la siguiente do statement while ( expression ) ;. Dicho esto, espero que se entienda, quise decir el ejemplo como una broma.
Escualo
321

Un libro que leí (no recuerdo correctamente qué libro) decía: Los compiladores intentan analizar las expresiones al token más grande usando la regla izquierda derecha.

En este caso, la expresión:

x-->0

Parses a tokens más grandes:

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

La misma regla se aplica a esta expresión:

a-----b

Después de analizar:

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

Espero que esto ayude a entender la expresión complicada ^^

NguyenDat
fuente
98
Su segunda explicación no es correcta. El compilador verá a-----by pensará (a--)-- - b, lo que no se compila porque a--no devuelve un valor l.
Tim Leaf
22
Además, xy --son dos fichas separadas.
Roland Illig
23
@DoctorT: pasa el lexer. solo el pase semántico es capaz de emitir ese error. entonces su explicación es correcta.
v.oddou
99
Siempre que piense que -->es un operador (que es lo que implica tener la pregunta que se le hizo), esta respuesta no es útil en absoluto: pensará que el token 2 es -->, no solo --. Si sabe que -->no es un operador, probablemente no tenga problemas para comprender el código de la pregunta, por lo tanto, a menos que tenga una pregunta completamente diferente, no estoy realmente seguro de cómo podría ser útil.
Bernhard Barker
44
El ejemplo de @DoctorT puede ser correcto suponiendo que se aha sobrecargado el operador posterior a la disminución, que devuelve lvalue. coliru.stacked-crooked.com/a/e1effc351ae79e9f
doc
275

Esto es exactamente lo mismo que

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

para números no negativos

Buena persona
fuente
153
¿No debería ser esto for(--x++;--x;++x--)?
Mateen Ulhaq
99
@DoctorT para eso unsignedes
Cole Johnson
12
@MateenUlhaq, eso está mal de acuerdo con el estándar, la expresión --x++tiene un comportamiento indefinido de acuerdo con §1.9.15
WorldSEnder
Si lo estuviera usando unsigned, lo habría usado%u
Cacahuete Frito
242

De todos modos, tenemos un operador "va a" ahora. "-->"es fácil de recordar como una dirección, y "mientras x va a cero" tiene sentido directo.

Además, es un poco más eficiente que "for (x = 10; x > 0; x --)"en algunas plataformas.

Prueba
fuente
17
No puede ser cierto siempre, especialmente cuando el valor de x es negativo.
Ganesh Gopalasubramanian
15
La otra versión no hace lo mismo: con for (size_t x=10; x-->0; )el cuerpo del bucle se ejecuta con 9,8, .., 0, mientras que la otra versión tiene 10,9, .., 1. De lo contrario, es bastante complicado salir de un ciclo a cero con una variable sin signo.
Pete Kirkham
44
Creo que esto es un poco engañoso ... No tenemos un operador literalmente "ir a", ya que necesitamos otro ++>para hacer el trabajo incremental.
tslmy
19
@Josh: en realidad, el desbordamiento da un comportamiento indefinido, por intlo que podría comerse a su perro con la misma facilidad que llevar xa cero si comienza negativo.
SamB
3
Este es un idioma muy importante para mí por la razón dada en el comentario de @PeteKirkham, ya que a menudo necesito hacer bucles decrecientes sobre cantidades sin firmar hasta el final 0. (A modo de comparación, el idioma de omitir pruebas para cero, como escribir en while (n--)lugar de no firmado n, no le compra nada y para mí obstaculiza enormemente la legibilidad). También tiene la agradable propiedad de que especifique uno más que el índice inicial, que generalmente es lo que que desee (por ejemplo, para un bucle sobre una matriz, especifique su tamaño). También me gusta -->sin espacio, ya que esto hace que el idioma sea fácil de reconocer.
Marc van Leeuwen
221

Este código primero compara xy 0 y luego disminuye x. (También se dice en la primera respuesta: estás decrementando x y luego comparando x y 0 con el >operador). Mira la salida de este código:

9 8 7 6 5 4 3 2 1 0

Ahora primero comparamos y luego disminuimos al ver 0 en la salida.

Si queremos primero disminuir y luego 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;
}

Esa salida es:

9 8 7 6 5 4 3 2 1
SjB
fuente
177

Mi compilador imprimirá 9876543210 cuando ejecute este código.

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

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

Como se esperaba. El while( x-- > 0 )realmente significa while( x > 0). Los x--decretos posteriores x.

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

Es una forma diferente de escribir lo mismo.

Sin embargo, es bueno que el original se vea como "mientras x va a 0".

cool_me5000
fuente
44
El resultado solo está indefinido cuando está incrementando / decrementando la misma variable más de una vez en la misma instrucción. No se aplica a esta situación.
Tim Leaf
13
while( x-- > 0 ) actually means while( x > 0)- No estoy seguro de lo que intentabas decir allí, pero la forma en que lo expresaste implica que --no tiene ningún significado, lo que obviamente es muy incorrecto.
Bernhard Barker
Para llevar el punto a casa desde @Dukeling, esta respuesta no es la misma que la publicación original. En la publicación original, xserá -1después de que salga del bucle, mientras que en esta respuesta, xserá 0.
Mark Lakata
148

Falta un espacio entre --y >. xes posterior decrementado, es decir, decrementado después de verificar la condición x>0 ?.

Sr. X
fuente
42
No falta el espacio: C (++) ignora los espacios en blanco.
27
@ H2CO3 Esto no es cierto en general. Hay lugares donde se debe utilizar el espacio en blanco para separar las fichas, por ejemplo, en #define foo()versus #define foo ().
Jens
30
@Jens ¿Qué tal: "No falta el espacio - C (++) ignora los espacios en blanco innecesarios"?
Kevin P. Rice
139

--es el operador de decremento y >es el operador mayor que .

Los dos operadores se aplican como uno solo -->.

muntoo
fuente
11
Se aplican como los 2 operadores separados que son. Solo están escritos de manera engañosa para que parezcan "uno solo".
underscore_d
129

Es una combinación de dos operadores. Primero --es para disminuir el valor, y >es para verificar si el valor es mayor que el operando de la derecha.

#include<stdio.h>

int main()
{
    int x = 10;

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

    return 0;
}

El resultado será:

9 8 7 6 5 4 3 2 1 0            
Rajeev Das
fuente
122

En realidad, xestá disminuyendo posteriormente y con esa condición se está comprobando. No es -->, es(x--) > 0

Nota: el valor de xse cambia después de que se verifica la condición, porque se reduce posteriormente. Algunos casos similares también pueden ocurrir, por ejemplo:

-->    x-->0
++>    x++>0
-->=   x-->=0
++>=   x++>=0
AndroidLearner
fuente
66
Excepto que ++> difícilmente puede usarse en un momento (). Un operador "sube a ..." sería ++ <, que no se ve tan bien en ningún lado. El operador -> es una feliz coincidencia.
Florian F
2
@BenLeggiero Eso podría 'funcionar' en el sentido de generar código que haga algo (mientras enfurece a los lectores que no les gusta el código falso), pero la semántica es diferente, ya que su uso de predecremento significa que ejecutará una iteración menos. Como ejemplo artificial, nunca ejecutaría el cuerpo del bucle si se xiniciara en 1, pero lo while ( (x--) > 0 )haría. {editar} Eric Lippert cubrió ambos en sus notas de lanzamiento de C # 4: blogs.msdn.microsoft.com/ericlippert/2010/04/01/…
underscore_d
120

C y C ++ obedecen la regla de "munch máximo". De la misma manera a a b se traduce (a--) - b, en su caso se x-->0traduce a (x--)>0.

Lo que la regla dice esencialmente es que yendo de izquierda a derecha, las expresiones se forman tomando el máximo de caracteres que formarán una expresión válida.

Peter Mortensen
fuente
55
Que es lo que asumió el OP: que "((a) ->)" era el munch máximo. Resulta que la suposición original del OP era incorrecta: "->" no es un operador válido máximo.
David
44
También conocido como análisis codicioso, si no recuerdo mal.
Roy Tinker
1
@RoyTinker Escaneo codicioso . El analizador no tiene nada que ver con esto.
Marqués de Lorne
27

¿Por qué toda la complicación?

La respuesta simple a la pregunta original es simplemente:

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

Hace lo mismo. No digo que debas hacerlo así, pero hace lo mismo y habría respondido la pregunta en una publicación.

El x--es solo una abreviatura de lo anterior, y >es solo un normal mayor que operator. No hay gran misterio!

Hay demasiada gente haciendo las cosas simples complicadas hoy en día;)

Garry_G
fuente
17
Esta pregunta no se trata de complicaciones, sino de ** Características ocultas y esquinas oscuras de C ++ / STL **
pix
20
El programa aquí proporciona una salida diferente a la original porque x aquí se reduce después de printf. Eso demuestra bien cómo las "respuestas simples" suelen ser incorrectas.
Öö Tiib
2
The OP's way: 9 8 7 6 5 4 3 2 1 0yThe Garry_G way: 10 9 8 7 6 5 4 3 2 1
Anthony
2
No hace lo mismo. Mueve tu x=x-1antes, printfentonces puedes decir "hace lo mismo".
CITBL
26

De la manera convencional, definiríamos una condición en el whileparéntesis del bucle ()y una condición de terminación dentro de los corchetes {}, pero -->define ambos a la vez.

Por ejemplo:

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

Esto disminuye ay ejecuta el ciclo mientras aes mayor que 0.

Convencionalmente, sería como:

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

En ambos sentidos, hacemos lo mismo y alcanzamos los mismos objetivos.

Zohaib Ejaz
fuente
55
Esto es incorrecto. El código en la pregunta hace: 'test-write-execute' (prueba primero, escribe un nuevo valor, ejecuta el ciclo), tu ejemplo es 'test-execute-write'.
v010dya
@ v010dya Se corrigió la respuesta, ahora es test-write-executecomo en la pregunta, ¡gracias por señalar!
Kotauskas
@VladislavToncharov Tu edición aún estaba mal. Mira el mio.
SS Anne
8

(x --> 0) medio (x-- > 0)

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

  2. puedes usar (-- x > 0) Es malo(--x > 0)
    output -: 9 8 7 6 5 4 3 2 1

  3. puedes usar
(--\
    \
     x > 0)

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

  1. puedes usar
(\
  \
   x --> 0)

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

  1. puedes usar
(\
  \
   x --> 0
          \
           \
            )

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

  1. puedes usar también
(
 x 
  --> 
      0
       )

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

Del mismo modo, puede probar muchos métodos para ejecutar este comando con éxito

Kalana
fuente