¿Qué hace que los desarrolladores de C sean tan curiosos si "i ++ == ++ i"? [cerrado]

15

Solo una observación aleatoria, parece que en StackOverflow.com, hay preguntas sobre si "++ i == i ++". Sin embargo, esa pregunta se hace todo el tiempo, creo que la vi planteada unas 6 o 7 veces en los últimos 2 meses.

Me pregunto por qué los desarrolladores de C están tan interesados ​​en él. También existe el mismo concepto / pregunta para los desarrolladores de C # y Java, pero creo que vi solo una pregunta relacionada con C #.

¿Es porque tantos ejemplos usan ++ i? ¿Es porque hay algún libro popular o tutorial? ¿Es porque a los desarrolladores de C les encanta agrupar tanto como sea posible en una sola línea para 'eficiencia' / 'rendimiento' y, por lo tanto, encuentran construcciones 'extrañas' usando el operador ++ con más frecuencia?

Michael Stum
fuente
23
(Para mí, como desarrollador de C #, i ++ y ++ son iguales. Sé que no lo son, pero si escribo un código que depende de la diferencia, prefiero refactorizarlo para que sea más legible y espero que el compilador y JITter se cuiden de eso, pero como desarrollador de C # no estoy tratando de ahorrar uno o dos ciclos de reloj porque ya soy relativamente ineficiente de todos modos)
Michael Stum
1
Como programadores en ciernes, nos encanta jugar con la aritmética, la lógica y tenemos curiosidad por saber cómo funcionan las cosas. Creo que es una gran razón por la que a los novatos nos encantan esas preguntas. Puede que no sea una función innovadora, ¡pero seguro que es interesante! ¿No es esa la razón por la que nos convertimos en programadores en primer lugar?
Chani
2
¿Se está refiriendo literalmente a la expresión ++i == i++, o más generalmente sobre la diferencia de significado entre ++iy i++?
Keith Thompson

Respuestas:

30

Sospecho que al menos parte de esto es un poco más simple: incluso ahora, vemos muchas preguntas como esta comenzando alrededor del comienzo del año escolar, y se van reduciendo gradualmente durante todo el año.

Como tal, creo que es justo adivinar que bastantes de ellos son simplemente el resultado de clases en las que el maestro habla al menos un poco al respecto, pero no explica muy bien su (s) punto (s). porque él realmente no los entiende). Especialmente en función de las personas que parecen hacer estas preguntas, pocas se basan en la codificación real.

Jerry Coffin
fuente
14
¿No es esto lo contrario de Eternal September? El eterno septiembre fue cuando AOL comenzó a ofrecer acceso a Usenet a sus clientes, lo que hace que parezca septiembre (el mes en que los nuevos estudiantes que comienzan la escuela tradicionalmente bombardearon los tableros como novatos) durante todo el año.
nlawalker
Es una teoría interesante, pero tal vez no siempre es culpa de los maestros si alguien no entendió el material: tal vez los estudiantes (1) no prestaban suficiente atención durante la clase y (2) eran demasiado flojos para buscar una respuesta en stackoverflow antes haciendo la misma pregunta de nuevo.
Giorgio
12

Porque los programadores C TIENEN que entender el orden de las operaciones. Los desarrolladores de C # no usan necesariamente los operadores bit a bit (&, |, ~) o los operadores de prefijo, ya que normalmente estamos más preocupados por otras cosas. Sin embargo, de lo que los desarrolladores de C # no nos damos cuenta es que debemos saber qué hacen los operadores que usamos a diario y cómo usarlos correctamente. La mayoría de nosotros evitamos los lugares donde esto puede ser un problema.

Fuera de la cabeza, ¿cuál es el resultado de este fragmento?

    double x = 5.5;
    Console.WriteLine(x++);
    x = 5.5;
    Console.WriteLine(++x);

Diría que un buen número de desarrolladores experimentados de C # no tienen idea de cuál es la salida a la consola.

Nate Noonen
fuente
3
+1. Conocer la diferencia entre los operadores de incremento / decremento previo y posterior al arreglo vale la pena para situaciones como esta.
Maulrus el
44
Veo un poco el punto y tampoco sabría la salida (creo que es 5.5 y 6.5, pero no estoy seguro), y para mí no importaría, ya que lo refactorizaría a x ++; Console.WriteLine (x); inmediatamente. Sin embargo, no soy totalmente ignorante, solo creo que es un gran olor a código con cero usabilidad.
Michael Stum
99
La respuesta a la pregunta no tiene nada que ver con el orden de las operaciones, o la diferencia entre los incrementos de prefijo y postfijo. Es una cuestión de comportamiento definido e indefinido.
David Thornley
2
Encontré esto hoy. Algo así como if (myList[i++] == item). Inteligente. Lo encontré buscando la fuente de una excepción IndexOutOfRange ... De hecho, muy "inteligente".
rmac
77
Creo que es 5.5 y 6.5, pero nunca antes lo había ++usado en una carroza, y debo decir que no se siente muy apropiado. ¿La gente hace eso? (Prefiero += 1)
Bart van Heukelom
8

Creo que esto es obvio. En C #, para an int i, i++ == ++isiempre es falso mientras++i == i++ que siempre es cierto, de manera confiable, y todos los interesados ​​pueden descubrirlo fácilmente simplemente aprendiendo las reglas de C # (o simplemente ejecutándolo).

En C y C ++, por otro lado, está casi indefinido porque depende del compilador, el entorno de ejecución, la plataforma, etc., por lo que es una pregunta mucho más difícil de responder, por lo que mucha gente la pregunta.

Timwi
fuente
+1 - pero en realidad no es una pregunta más difícil de responder. "indefinido" es una palabra. Todas las cosas de "depende de ..." son cosas de las que la mayoría de la gente no se preocupa. Incluso si solo está escribiendo para una plataforma en particular, debería usar los modismos normales para el lenguaje en su conjunto, y la mayoría de los usos de operadores de incremento previo y posterior son parte de algunos modismos comunes.
Steve314
+1: Esto realmente responde la pregunta (es decir, no estás leyendo entre líneas).
Thomas Eding
7

Es una pregunta popular porque es una pregunta capciosa. Es indefinido .

El enlace de arriba va a Preguntas frecuentes en la página de inicio de Bjarnes Stroustrup, que aborda esta pregunta específicamente y explica por qué esta construcción no está definida. Lo que dice es:

Básicamente, en C y C ++, si lee una variable dos veces en una expresión donde también la escribe, el resultado es indefinido.

Al afirmar que el orden de evaluación no está definido, se obtiene un código de mejor rendimiento.

usuario16764
fuente
5

Lo más probable es que en C, realmente importa si escribes i++o ++icuando estás haciendo aritmética de puntero. Allí, aumentandoi antes o después de una operación podría ser crucial. Te daría un ejemplo, pero la última vez que escribí C fue hace 10 años ...

En C #, nunca me he encontrado con una situación que me obligue a pensar i++o ++iporque AFAIK, para los bucles for / while, realmente no importa.

Mladen Prajdic
fuente
3
sigue siendo importante entender las diferencias en C #, solo porque parece que solo las usa para / para cada bucle no significa que ese sea el único lugar donde las encontrará
STW
totalmente cierto eso.
Mladen Prajdic
3
Esto no es relevante para la pregunta. La pregunta no es sobre la diferencia entre i++y ++i, sino combinarlos en la misma expresión.
David Thornley
@David La pregunta es por qué los programadores de C tienen curiosidad al respecto. La respuesta (Importa en C, no tanto en C #) es completamente relevante ".
Florian F
2

Hace unos años leí que estos operadores se consideraban peligrosos, así que traté de obtener más información al respecto. Si stackoverflow hubiera estado activo en ese momento, lo habría preguntado allí.

Ahora es porque algunas personas retorcidas escriben bucles como

while( [something] )
{
  a[++j] = ++j;
}

Incluso ahora, no estoy muy seguro de lo que sucederá / debería suceder, pero para mí es bastante claro que múltiples ++ [var] en la misma línea están buscando problemas.

Eric
fuente
2
Los incrementos tienen un comportamiento indefinido como parte de una tarea en C
tzenes el
77
Las asignaciones como x = ++j;están bien definidas en C. Lo anterior no está definido porque jse modifica dos veces sin puntos de secuencia intermedios.
Matthew Flaschen
2

Dos razones.

La implementación correcta de ++ i es incrementar i y luego devolverlo. La implementación correcta de i ++ es guardar el valor actual, incrementar i y devolver el valor guardado. Saber que estos no se implementan como sinónimos es importante.

La pregunta entonces es cuándo los aplica el compilador al evaluar una expresión, como la igualdad.

Si la prueba de igualdad se realiza primero, luego los operadores anteriores y posteriores al incremento, tendrá que escribir una lógica diferente que si el lado izquierdo (lhs) y el lado derecho (rhs) se evalúan primero, luego la igualdad.

Se trata del orden de las operaciones, y eso a su vez afecta el código que uno escribe. Y, como era de esperar, no todos los idiomas están de acuerdo.

La lista de pruebas básicas permite a los desarrolladores probar si sus suposiciones son correctas y si la implementación real coincide con la especificación del lenguaje.

Esto puede tener todo tipo de impacto cuando se trabaja con punteros, bucles o valores de retorno.

Walt Stoneburner
fuente
55
Las pruebas básicas sobre esto serán engañosas, porque es un comportamiento indefinido. Si funciona exactamente como espera esta vez, no hay garantía de que lo haga la próxima vez.
David Thornley
Has respondido la pregunta equivocada. Debería responder por qué los programadores de C tienen curiosidad al respecto.
Hugo
Su segundo parámetro es incorrecto de todos modos (antes de C ++ 11, al menos): el comportamiento de ++ies usar el valori+1 y en algún momento, quizás antes o después de eso, pero antes del siguiente punto de secuencia, incrementei .
MM
@MattMcNabb: ¿Me puede indicar una especificación para eso? Me gustaría saber si las cosas han cambiado en la implementación. En los días en que C se asignaba muy bien al ensamblaje de PDP, ++ i inyectaba una instrucción INC, mientras que la versión de sufijo tenía que copiar el valor en un registro para usar una instrucción después del incremento. ¿Qué constituía la necesidad del cambio que describiste?
Walt Stoneburner
2

Creo que es un choque cultural.

Como ya se señaló, el comportamiento de una expresión en C o C ++ puede ser indefinido porque el orden de ejecución de los incrementos posteriores, etc., no está estrictamente definido. El comportamiento indefinido es bastante común en C y, por supuesto, gran parte de eso se importó a C ++.

Para alguien que ha programado algo en otro idioma, alguien que ha captado la idea de que se supone que los lenguajes de programación son precisos y que las computadoras deben hacer lo que se les dice que hagan ... bueno, es un shock descubre que C es intencionalmente vago sobre algunas cosas.

Steve314
fuente
C es así porque fue diseñado para admitir muchas más plataformas de las que existían cuando se definió C #, incluidas las plataformas incrustadas o mainframe más extrañas que pueda imaginar. C #, por otro lado, se ejecuta en ... x86 y 360? tal vez ARM también? Nada más. Es por eso que C # puede definir mucho más.
DeadMG
++ Además, ¿no se construyó C por primera vez en un PDP-11? ¿Dónde había instrucciones de incremento automático? C quería estar "cerca de la máquina" para poder hacer un uso útil del conjunto de instrucciones.
Mike Dunlavey
@MikeDunlavey: No, las C ++y los --operadores no se basaban en el PDP-11, que no existía cuando esos operadores se introdujeron en el lenguaje B predecesor de C Ver cm.bell-labs.com/who/dmr/chist.html , y busque "incremento automático".
Keith Thompson
1

Tal vez es solo que los desarrolladores de C usan el incremento de ++ más a menudo en general, ya que C no tiene "foreach" o una declaración similar para recorrer los arreglos. ¡Ah, y por supuesto, el puntero aritmático, como se mencionó anteriormente!

Robert Roos
fuente
1
Buen punto, olvidé que foreach es un concepto relativamente moderno.
Michael Stum
-1

La diferencia entre ambas partes: la publicación y el preincremento funcionan de la manera en que estas dos piezas de código deberían funcionar en todos los idiomas. ¡ESTO NO ES DEPENDIENTE DEL LENGUAJE!

++i

Esto es pre incremento. Este fragmento de código aumentará primero el valor de iantes de enviar el valor a la línea donde se usa.

i++

Este es el incremento posterior. Este código devolverá el valor de iantes de que aumente el valor dei en la línea donde se usa.

En otro pequeño ejemplo:

int main(void)
{
  int i = 0; 
  int result; 
  result = 10 + ++i; 
  printf("%d \n", result); // = 11 

  int j = 0; 
  result = 10 + j++; 
  printf("%d \n", result);// = 10
  return 0;
}

Este código compila con resultados en el teclado.

Esto tiene que ver con la implementación interna de la sobrecarga del operador.

++i aumenta directamente el valor (y, por lo tanto, es un poco más rápido)

i++ primero crea una copia que se devuelve al lugar donde se necesita y luego el valor original del i variable aumenta en uno.

Espero que esto esté claro ahora.

Krie999
fuente
Sin embargo, esto no aborda la pregunta real: ¿por qué los desarrolladores de C preguntan sobre esto más que otros? El OP entiende a los operadores.
Martijn Pieters
También esta respuesta es objetivamente incorrecta. ++ino es más rápido y i++no crea una copia. Además, se ++icomporta de manera ligeramente diferente en C que en C ++, y mucho menos entre otros lenguajes.
MM