¿Hay alguna diferencia de rendimiento entre i ++ y ++ i en C?

Respuestas:

397

Resumen ejecutivo: no.

i++potencialmente podría ser más lento que ++i, ya que el valor anterior de i podría necesitar guardarse para su uso posterior, pero en la práctica todos los compiladores modernos optimizarán esto.

Podemos demostrar esto mirando el código de esta función, tanto con ++iy i++.

$ cat i++.c
extern void g(int i);
void f()
{
    int i;

    for (i = 0; i < 100; i++)
        g(i);

}

Los archivos son iguales, excepto por ++iy i++:

$ diff i++.c ++i.c
6c6
<     for (i = 0; i < 100; i++)
---
>     for (i = 0; i < 100; ++i)

Los compilaremos y también obtendremos el ensamblador generado:

$ gcc -c i++.c ++i.c
$ gcc -S i++.c ++i.c

Y podemos ver que tanto el objeto generado como los archivos ensambladores son iguales.

$ md5 i++.s ++i.s
MD5 (i++.s) = 90f620dda862cd0205cd5db1f2c8c06e
MD5 (++i.s) = 90f620dda862cd0205cd5db1f2c8c06e

$ md5 *.o
MD5 (++i.o) = dd3ef1408d3a9e4287facccec53f7d22
MD5 (i++.o) = dd3ef1408d3a9e4287facccec53f7d22
Mark Harrison
fuente
99
Sé que esta pregunta es sobre C, pero me interesaría saber si los navegadores pueden hacer esta optimización para javascript.
TM.
69
Entonces el "No" es verdadero para el compilador con el que probó.
Andreas
173
@ Andrea: Buena pregunta. Solía ​​ser un escritor de compiladores, y tuve la oportunidad de probar este código en muchas CPU, sistemas operativos y compiladores. El único compilador que encontré que no optimizó el caso de i ++ (de hecho, el compilador que me llamó la atención profesionalmente) fue el compilador Software Toolworks C80 de Walt Bilofsky. Ese compilador fue para sistemas Intel 8080 CP / M. Es seguro decir que cualquier compilador que no incluya esta optimización no es para uso general.
Mark Harrison el
22
Aunque la diferencia de rendimiento es insignificante y está optimizada en muchos casos, tenga en cuenta que todavía es una buena práctica usarla en ++ilugar de hacerlo i++. No hay absolutamente ninguna razón para no hacerlo, y si su software pasa a través de una cadena de herramientas que no lo optimiza, su software será más eficiente. Teniendo en cuenta que es tan fácil de escribir ++icomo de escribir i++, realmente no hay excusa para no estar usando ++ien primer lugar.
monokrome
77
@monokrome Dado que los desarrolladores pueden proporcionar su propia implementación para los operadores de prefijos y postfijos en muchos idiomas, esta no siempre es una solución aceptable para un compilador sin comparar primero esas funciones, lo que puede no ser trivial.
pickypg
112

De Eficiencia versus intención de Andrew Koenig:

Primero, está lejos de ser obvio que ++isea ​​más eficiente que i++, al menos en lo que respecta a las variables enteras.

Y:

Entonces, la pregunta que uno debería hacerse no es cuál de estas dos operaciones es más rápida, sino cuál de estas dos operaciones expresa con mayor precisión lo que está tratando de lograr. Debo afirmar que si no está utilizando el valor de la expresión, nunca hay una razón para usar i++en su lugar ++i, porque nunca hay una razón para copiar el valor de una variable, incrementar la variable y luego tirar la copia.

Entonces, si no se usa el valor resultante, lo usaría ++i. Pero no porque sea más eficiente: porque indica correctamente mi intención.

Sébastien RoccaSerra
fuente
55
No olvidemos que otros operadores unarios también son prefijos. Creo que ++ i es la forma "semántica" de usar un operador unario, mientras que i ++ está disponible para ajustarse a una necesidad específica (evaluación antes de la adición).
TM.
99
Si no se usa el valor resultante, no hay diferencia en la semántica: es decir, no hay base para preferir una u otra construcción.
Eamon Nerbonne
3
Como lector, veo una diferencia. Como escritor, mostraré mi intención eligiendo uno sobre el otro. Es solo un hábito que tengo, tratar de comunicarme con mis amigos programadores y compañeros de equipo a través del código :)
Sébastien RoccaSerra
11
Siguiendo el consejo de Koenig, codifico de i++la misma manera que codifico i += no i = i + n, es decir, en la forma objeto del verbo objetivo , con el operando objetivo a la izquierda del operador verbal . En el caso de i++, no hay un objeto correcto , pero la regla aún se aplica, manteniendo el objetivo a la izquierda del operador verbal .
David R Tribble
44
Si está intentando incrementar i, entonces i ++ y ++ i ambos expresan correctamente su intención. No hay razón para preferir uno sobre el otro. Como lector, no veo ninguna diferencia, ¿se confunden sus colegas cuando ven i ++ y piensan, tal vez esto es un error tipográfico y no quiso aumentar i?
Dan Carter
46

Una mejor respuesta es que ++ia veces será más rápido pero nunca más lento.

Todo el mundo parece estar asumiendo que ies un tipo incorporado normal como int. En este caso no habrá diferencia medible.

Sin embargo, si ies de tipo complejo, puede encontrar una diferencia medible. Para ello i++debe hacer una copia de su clase antes de incrementarla. Dependiendo de lo que esté involucrado en una copia, de hecho podría ser más lento ya que con ++itusted solo puede devolver el valor final.

Foo Foo::operator++()
{
  Foo oldFoo = *this; // copy existing value - could be slow
  // yadda yadda, do increment
  return oldFoo;
}

Otra diferencia es que con ++iusted tiene la opción de devolver una referencia en lugar de un valor. Nuevamente, dependiendo de lo que esté involucrado en hacer una copia de su objeto, esto podría ser más lento.

Un ejemplo del mundo real de dónde puede ocurrir esto sería el uso de iteradores. Es poco probable que copiar un iterador sea un cuello de botella en su aplicación, pero sigue siendo una buena práctica adquirir el hábito de usar en ++ilugar de i++donde el resultado no se ve afectado.

Andrew Grant
fuente
36
La pregunta establece explícitamente C, sin referencia a C ++.
Dan Cristoloveanu
55
Esta pregunta (ciertamente antigua) se refería a C, no a C ++, pero creo que también vale la pena mencionar que, en C ++, incluso si una clase implementa operadores posteriores y previos, ni siquiera están necesariamente relacionados. Por ejemplo, la barra ++ puede incrementar un miembro de datos, mientras que la barra ++ puede incrementar un miembro de datos diferente y, en este caso, tampoco tendría la opción de usar, ya que la semántica es diferente.
Kevin
-1 Si bien este es un buen consejo para los programadores de C ++, no responde a la pregunta, que está etiquetada con C, en lo más mínimo. En C, no hace ninguna diferencia si usa prefijo o postfix.
Lundin
@Pacerier La pregunta está etiquetada como C y solo C. ¿Por qué asumes que no están interesados ​​en eso? Dado cómo funciona SO, ¿no sería inteligente suponer que solo están interesados ​​en C, en lugar de Java, C #, COBOL o cualquier otro lenguaje fuera de tema?
Lundin
18

Respuesta corta:

Nunca hay diferencia entre i++y ++ien términos de velocidad. Un buen compilador no debería generar un código diferente en los dos casos.

Respuesta larga:

Lo que cualquier otra respuesta no menciona es que la diferencia entre ++iversus i++solo tiene sentido dentro de la expresión que se encuentra.

En el caso de for(i=0; i<n; i++), el i++está solo en su propia expresión: hay un punto de secuencia antes del i++y hay uno después. Por lo tanto, el único código de máquina generado es "aumentar ien 1" y está bien definido cómo se secuencia esto en relación con el resto del programa. Entonces, si lo cambiara a prefijo ++, no importaría en lo más mínimo, todavía obtendría el código de la máquina "aumentar ien 1".

Las diferencias entre ++iy i++solo importan en expresiones como array[i++] = x;versus array[++i] = x;. Algunos pueden argumentar y decir que el postfix será más lento en tales operaciones porque el registro donde ireside tiene que volver a cargarse más tarde. Pero luego tenga en cuenta que el compilador es libre de ordenar sus instrucciones de la forma que desee, siempre y cuando no "rompa el comportamiento de la máquina abstracta" como lo llama el estándar C.

Entonces, si bien puede suponer que array[i++] = x;se traduce al código de la máquina como:

  • Almacene el valor ien el registro A.
  • Almacene la dirección de la matriz en el registro B.
  • Agregue A y B, almacene los resultados en A.
  • En esta nueva dirección representada por A, almacene el valor de x.
  • Almacene el valor ien el registro A // ineficiente porque aquí hay instrucciones adicionales, ya lo hicimos una vez.
  • Incremento registro A.
  • Almacenar el registro A en i.

el compilador también podría producir el código de manera más eficiente, como:

  • Almacene el valor ien el registro A.
  • Almacene la dirección de la matriz en el registro B.
  • Agregue A y B, almacene los resultados en B.
  • Incremento registro A.
  • Almacenar el registro A en i.
  • ... // resto del código.

Solo porque usted como programador en C está capacitado para pensar que el postfix ++ocurre al final, el código de la máquina no tiene que ser ordenado de esa manera.

Por lo tanto, no hay diferencia entre el prefijo y el postfix ++en C. Ahora, lo que usted como programador en C debe variar es la gente que inconsistentemente usa el prefijo en algunos casos y postfix en otros casos, sin ninguna razón. Esto sugiere que no están seguros de cómo funciona C o que tienen un conocimiento incorrecto del lenguaje. Esto siempre es una mala señal, ya que a su vez sugiere que están tomando otras decisiones cuestionables en su programa, basadas en supersticiones o "dogmas religiosos".

"El prefijo ++siempre es más rápido" es uno de esos dogmas falsos que es común entre los posibles programadores en C.

Lundin
fuente
3
Nadie dijo "Prefix ++ siempre es más rápido". Eso está mal citado. Lo que dijeron fue "Postfix ++ nunca es más rápido".
Pacerier
2
@Pacerier No estoy citando a ninguna persona en particular, sino solo una creencia incorrecta e generalizada.
Lundin
@rbaleksandar C ++! = C.
Lundin
@rbaleksandar La pregunta y la respuesta hablan sobre C ++. Que es diferente de C, ya que tiene sobrecarga de operadores y constructores de copia, etc.
Lundin
3
@rbaleksandar c ++ == c && ++ c! = c
sadljkfhalskdjfh
17

Tomando una hoja de Scott Meyers, Más eficaz c ++ Elemento 6: Distinga entre las formas de prefijo y postfijo de las operaciones de incremento y decremento .

La versión del prefijo siempre se prefiere sobre el postfix en lo que respecta a los objetos, especialmente en lo que respecta a los iteradores.

La razón de esto si observa el patrón de llamada de los operadores.

// Prefix
Integer& Integer::operator++()
{
    *this += 1;
    return *this;
}

// Postfix
const Integer Integer::operator++(int)
{
    Integer oldValue = *this;
    ++(*this);
    return oldValue;
}

Mirando este ejemplo, es fácil ver cómo el operador de prefijo siempre será más eficiente que el postfix. Debido a la necesidad de un objeto temporal en el uso del postfix.

Es por eso que cuando ve ejemplos que usan iteradores, siempre usan la versión de prefijo.

Pero como señala para int, efectivamente no hay diferencia debido a la optimización del compilador que puede tener lugar.

JProgrammer
fuente
44
Creo que su pregunta estaba dirigida a C, pero para C ++ tienes toda la razón, y además las personas C deberían adoptar esto, ya que también pueden usarlo para C ++. Con demasiada frecuencia veo que los programadores de C usan la sintaxis de postfix ;-)
Anders Rune Jensen
-1 Si bien este es un buen consejo para los programadores de C ++, no responde a la pregunta, que está etiquetada con C, en lo más mínimo. En C, no hace ninguna diferencia si usa prefijo o postfix.
Lundin
1
El prefijo @Lundin y el postifx son importantes en C según la respuesta de Andreas . No puede suponer que el compilador se optimizará, y es una buena práctica que Alwas prefiera ++ i sobre i ++
JProgrammer
@JProgrammer No importan según la respuesta de los suyos sinceramente :) Si descubre que producen un código diferente, es porque no pudo habilitar las optimizaciones o porque el compilador es malo. De todos modos, su respuesta está fuera de tema ya que la pregunta era sobre C.
Lundin
16

Aquí hay una observación adicional si le preocupa la micro optimización. Los bucles decrecientes pueden ser 'posiblemente' más eficientes que los bucles incrementales (dependiendo de la arquitectura del conjunto de instrucciones, por ejemplo, ARM), dado:

for (i = 0; i < 100; i++)

En cada bucle, tendrá una instrucción para:

  1. Agregando 1a i.
  2. Compare si ies menor que a 100.
  3. Una rama condicional si ies menor que a 100.

Mientras que un ciclo decreciente:

for (i = 100; i != 0; i--)

El ciclo tendrá una instrucción para cada uno de:

  1. Decremento i, configurando el indicador de estado del registro de la CPU.
  2. Una rama condicional que depende del estado del registro de la CPU ( Z==0).

¡Por supuesto, esto funciona solo cuando disminuye a cero!

Recordado en la Guía del desarrollador del sistema ARM.

tonylo
fuente
Bueno ¿Pero esto no crea menos visitas al caché?
AndreasT
Hay un viejo truco extraño de los libros de optimización de código, que combina la ventaja de la rama de prueba cero con la dirección incrementada. Aquí hay un ejemplo en lenguaje de alto nivel (probablemente inútil, ya que muchos compiladores son lo suficientemente inteligentes como para reemplazarlo con un código de bucle menos eficiente pero más común): int a [N]; para (i = -N; i; ++ i) a [N + i] + = 123;
noop
@noop, ¿podría explicar en qué libros de optimización de código se refiere? He luchado por encontrar buenos.
mezamórfico
77
Esta respuesta no es una respuesta a la pregunta en absoluto.
monokrome
@mezamorphic Para x86 mis fuentes son: manuales de optimización de Intel, Agner Fog, Paul Hsieh, Michael Abrash.
noop
11

No deje que la pregunta de "cuál es más rápido" sea el factor decisivo para usar. Es probable que nunca le importe tanto, y además, el tiempo de lectura del programador es mucho más costoso que el tiempo de la máquina.

Use el que tenga más sentido para el humano que lee el código.

Andy Lester
fuente
3
Creo que es incorrecto preferir mejoras vagas de legibilidad a las ganancias reales de eficiencia y la claridad general de la intención.
noop
44
Mi término "tiempo de lectura del programador" es más o menos análogo a "claridad de intención". Las "ganancias de eficiencia reales" a menudo son inconmensurables, lo suficientemente cercanas a cero para llamarlas cero. En el caso del OP, a menos que el código haya sido perfilado para encontrar que ++ i es un cuello de botella, la pregunta de cuál es más rápido es una pérdida de tiempo y unidades de pensamiento del programador.
Andy Lester
2
La diferencia en la legibilidad entre ++ i e i ++ es solo una cuestión de preferencia personal, pero ++ i implica claramente una operación más simple que i ++, a pesar de que el resultado es equivalente para casos triviales y tipos de datos simples cuando se trata de optimizar el compilador. Por lo tanto, ++ i es un ganador para mí, cuando las propiedades específicas del post-incremento no son necesarias.
noop
Estás diciendo lo que estoy diciendo. Es más importante mostrar intención y mejorar la legibilidad que preocuparse por la "eficiencia".
Andy Lester
2
Todavía no puedo estar de acuerdo. Si la legibilidad ocupa un lugar destacado en su lista de prioridades, tal vez su elección del lenguaje de programación sea incorrecta. El objetivo principal de C / C ++ es escribir código eficiente.
noop
11

En primer lugar: la diferencia entre i++y ++ies despreciable en C.


A los detalles.

1. El conocido problema de C ++: ++ies más rápido

En C ++, ++ies más eficiente si f ies algún tipo de objeto con un operador de incremento sobrecargado.

¿Por qué?
En ++i, el objeto se incrementa primero y luego puede pasar como referencia constante a cualquier otra función. Esto no es posible si la expresión se foo(i++)debe a que ahora se necesita hacer el incremento antes de foo()llamarlo, pero se debe pasar el valor anterior foo(). En consecuencia, el compilador se ve obligado a hacer una copia iantes de ejecutar el operador de incremento en el original. Las llamadas adicionales de constructor / destructor son la parte mala.

Como se señaló anteriormente, esto no se aplica a los tipos fundamentales.

2. El hecho poco conocido: i++ puede ser más rápido

Si no se necesita llamar a ningún constructor / destructor, que es siempre el caso en C, ++iy i++debería ser igualmente rápido, ¿verdad? No. Son prácticamente igual de rápidos, pero puede haber pequeñas diferencias, que la mayoría de los demás responden al revés.

¿Cómo puede i++ser más rápido?
El punto son las dependencias de datos. Si el valor necesita cargarse desde la memoria, se deben realizar dos operaciones posteriores con él, incrementándolo y usándolo. Con ++i, el incremento debe hacerse antes de que se pueda usar el valor. Con i++, el uso no depende del incremento, y la CPU puede realizar la operación de uso en paralelo a la operación de incremento. La diferencia es como máximo un ciclo de CPU, por lo que es realmente despreciable, pero está ahí. Y es al revés de lo que muchos esperarían.

cmaster - restablecer monica
fuente
Acerca de su punto 2: si el ++io i++se usa dentro de otra expresión, cambiar entre ellos cambia la semántica de la expresión, por lo que cualquier posible ganancia / pérdida de rendimiento está fuera de discusión. Si son independientes, es decir, el resultado de la operación no se usa inmediatamente, entonces cualquier compilador decente lo compilaría de la misma manera, por ejemplo, una INCinstrucción de ensamblaje.
Shahbaz
1
@Shahbaz Eso es perfectamente cierto, pero no es el punto. 1) A pesar de que la semántica es diferente, tanto i++y ++ipueden ser usados indistintamente en casi todas las situaciones posibles mediante el ajuste de las constantes de bucle por uno, así que están cerca equivalente en lo que hacen para el programador. 2) Aunque ambos compilan con la misma instrucción, su ejecución difiere para la CPU. En el caso de i++, la CPU puede calcular el incremento en paralelo con alguna otra instrucción que use el mismo valor (¡las CPU realmente hacen esto!), Mientras que con ++ila CPU tiene que programar la otra instrucción después del incremento.
cmaster - reinstalar a monica el
44
@Shahbaz Como ejemplo: if(++foo == 7) bar();y if(foo++ == 6) bar();son funcionalmente equivalentes. Sin embargo, el segundo puede ser un ciclo más rápido, ya que la CPU puede calcular en paralelo la comparación y el incremento. No es que este ciclo único importe mucho, pero la diferencia está ahí.
cmaster - reinstalar a monica el
1
Buen punto. Las constantes se muestran mucho (así como, <por ejemplo, vs <=) donde ++generalmente se usa, por lo que la conversión entre las imágenes suele ser fácilmente posible.
Shahbaz
1
Me gusta el punto 2, pero eso solo se aplica si se usa el valor, ¿verdad? La pregunta dice "si no se utiliza el valor resultante", por lo que puede ser confuso.
jinawee
7

@Mark Aunque el compilador puede optimizar la copia temporal (basada en pila) de la variable y gcc (en versiones recientes) lo hace, no significa que todos los compiladores siempre lo harán.

Lo acabo de probar con los compiladores que utilizamos en nuestro proyecto actual y 3 de cada 4 no lo optimizan.

Nunca suponga que el compilador lo hace bien, especialmente si el código posiblemente más rápido, pero nunca más lento, es tan fácil de leer.

Si no tiene una implementación realmente estúpida de uno de los operadores en su código:

Alwas prefiere ++ i sobre i ++.

Andreas
fuente
Simplemente curioso ... ¿por qué usas 4 compiladores de C diferentes en un proyecto? ¿O en un equipo o una compañía, para el caso?
Lawrence Dol
3
Al crear juegos para consolas, cada plataforma trae su propio compilador / cadena de herramientas. En un mundo perfecto podríamos usar gcc / clang / llvm para todos los objetivos, pero en este mundo tenemos que aguantar a Microsoft, Intel, Metroworks, Sony, etc.
Andreas
5

En C, el compilador generalmente puede optimizarlos para que sean los mismos si el resultado no se usa.

Sin embargo, en C ++ si usa otros tipos que proporcionan sus propios operadores ++, es probable que la versión del prefijo sea más rápida que la versión postfix. Entonces, si no necesita la semántica de postfix, es mejor usar el operador de prefijo.

Kristopher Johnson
fuente
4

Puedo pensar en una situación en la que postfix es más lento que el incremento de prefijo:

Imagine que Ase utiliza un procesador con registro como acumulador y es el único registro utilizado en muchas instrucciones (algunos microcontroladores pequeños son realmente así).

Ahora imagine el siguiente programa y su traducción en un montaje hipotético:

Incremento de prefijo:

a = ++b + c;

; increment b
LD    A, [&b]
INC   A
ST    A, [&b]

; add with c
ADD   A, [&c]

; store in a
ST    A, [&a]

Incremento de postfix:

a = b++ + c;

; load b
LD    A, [&b]

; add with c
ADD   A, [&c]

; store in a
ST    A, [&a]

; increment b
LD    A, [&b]
INC   A
ST    A, [&b]

Observe cómo bse forzó la recarga del valor de . Con el incremento de prefijo, el compilador puede simplemente incrementar el valor y seguir usándolo, posiblemente evitando volver a cargarlo ya que el valor deseado ya está en el registro después del incremento. Sin embargo, con el incremento de postfix, el compilador tiene que lidiar con dos valores, uno el antiguo y otro el valor incrementado que, como muestro arriba, da como resultado un acceso más a la memoria.

Por supuesto, si no se utiliza el valor del incremento, como una sola i++;declaración, el compilador puede (y lo hace) simplemente generar una instrucción de incremento independientemente del uso de prefijo o postfix.


Como nota al margen, me gustaría mencionar que una expresión en la que hay un b++no puede convertirse simplemente en una ++bsin ningún esfuerzo adicional (por ejemplo, agregando a - 1). Entonces, comparar los dos si son parte de alguna expresión no es realmente válido. A menudo, cuando usa b++dentro de una expresión que no puede usar ++b, por lo que incluso si ++bfuera potencialmente más eficiente, simplemente estaría mal. La excepción es, por supuesto, si la expresión lo está pidiendo (por ejemplo, a = b++ + 1;que se puede cambiar a a = ++b;).

Shahbaz
fuente
4

He estado leyendo a través de la mayor parte de las respuestas aquí y muchos de los comentarios, y yo no vi ninguna referencia a la una instancia que lo que podía pensar en que i++es más eficiente que ++i(y tal vez sorprendentemente --i era más eficiente que i--). ¡Eso es para los compiladores de C para el DEC PDP-11!

El PDP-11 tenía instrucciones de montaje para el decremento previo de un registro y el incremento posterior, pero no al revés. Las instrucciones permitieron que cualquier registro de "propósito general" se utilizara como un puntero de pila. Entonces, si usó algo así *(i++), podría compilarse en una sola instrucción de ensamblaje, mientras *(++i)que no podría.

Obviamente, este es un ejemplo muy esotérico, pero proporciona la excepción donde el incremento posterior es más eficiente (o debería decir que lo fue , ya que no hay mucha demanda de código PDP-11 C en estos días).

daShier
fuente
2
Muy esotérico, pero muy interesante!
Mark Harrison
@daShier. +1, aunque no estoy de acuerdo, esto no es tan esotérico, o al menos no debería serlo. C fue desarrollado conjuntamente con Unix en AT&T Bell Labs a principios de los años 70, cuando el PDP-11 era el procesador objetivo. En el código fuente de Unix de esta era, el incremento posterior, "i ++", es más frecuente en parte porque los desarrolladores sabían cuándo se asigna el valor, "j = i ++", o se usa como índice, "a [i ++] = n", el código sería un poco más rápido (y más pequeño). Parece que se acostumbraron a usar el incremento posterior a menos que se requiriera previamente. Otros aprendieron leyendo su código y también aprendieron este hábito.
jimhark
El 68000 tiene la misma característica, el incremento posterior y el decremento previo son compatibles con el hardware (como modos de direccionamiento), pero no al revés. El equipo de Motorola se inspiró en el DEC PDP-11.
jimhark
2
@jimhark, sí, soy uno de esos programadores PDP-11 que hicieron la transición al 68000 y todavía lo uso --iy i++.
daShier
2

Siempre prefiero pre-incremento, sin embargo ...

Quería señalar que incluso en el caso de llamar a la función operator ++, el compilador podrá optimizar lo temporal si la función se alinea. Dado que el operador ++ suele ser corto y a menudo implementado en el encabezado, es probable que se inserte.

Entonces, para fines prácticos, es probable que no haya mucha diferencia entre el rendimiento de las dos formas. Sin embargo, siempre prefiero el incremento previo, ya que parece mejor expresar directamente lo que estoy tratando de decir, en lugar de depender del optimizador para resolverlo.

Además, darle menos posibilidades al optimizador significa que el compilador se ejecuta más rápido.


fuente
Su publicación es específica para C ++, mientras que la pregunta es sobre C. En cualquier caso, su respuesta es incorrecta: para los operadores de post-incremento personalizados, el compilador generalmente no podrá producir un código tan eficiente.
Konrad Rudolph el
Él dice "si la función se alinea", y eso hace que su razonamiento sea correcto.
Blaisorblade
Dado que C no proporciona una sobrecarga del operador, la pregunta previa vs. posterior es, en gran medida, poco interesante. El compilador puede optimizar una temperatura no utilizada utilizando la misma lógica que se aplica a cualquier otro valor calculado primitivamente no utilizado. Vea la respuesta seleccionada para una muestra.
0

Mi C está un poco oxidada, así que me disculpo de antemano. Speedwise, puedo entender los resultados. Pero, estoy confundido sobre cómo ambos archivos salieron al mismo hash MD5. Tal vez un bucle for se ejecuta igual, pero ¿las siguientes 2 líneas de código no generarían un ensamblaje diferente?

myArray[i++] = "hello";

vs

myArray[++i] = "hello";

El primero escribe el valor en la matriz, luego incrementa i. Los segundos incrementos luego escribo en la matriz. No soy un experto en ensamblaje, pero simplemente no veo cómo se generaría el mismo ejecutable con estas 2 líneas de código diferentes.

Solo mis dos centavos.

Jason Z
fuente
1
@Jason Z La optimización del compilador ocurre antes de que se termine de generar el ensamblado, vería que la variable i no se usa en ningún otro lugar en la misma línea, por lo que mantener su valor sería un desperdicio, probablemente lo voltea efectivamente a i ++. Pero eso es solo una suposición. No puedo esperar hasta que uno de mis profesores intente decir que es más rápido y puedo ser el tipo que corrige una teoría con evidencia práctica. Ya casi puedo sentir la animosidad ^ _ ^
Tarks
3
"Mi C está un poco oxidada, así que me disculpo de antemano". No hay nada malo con su C, pero no leyó la pregunta original en su totalidad: "¿Existe una diferencia de rendimiento entre i ++ y ++ i si no se utiliza el valor resultante? " Tenga en cuenta las cursivas. En su ejemplo, se usa el 'resultado' de i ++ / ++ i , pero en el bucle idiomático for, el 'resultado' del operador pre / postincremento no se usa para que el compilador pueda hacer lo que quiera.
Roddy
2
en su ejemplo, el código sería diferente porque está usando el valor. el ejemplo en el que eran iguales solo usaba ++ para el incremento y no usaba el valor devuelto por ninguno.
John Gardner
1
Solución: "el compilador vería que el valor de retorno de i ++ no se utiliza, por lo que lo cambiará a ++ i". Lo que escribió también está mal porque no puede tener i junto con uno de i ++, i ++ en la misma línea (declaración), ese resultado no está definido.
Blaisorblade
1
Cambiar foo[i++]a foo[++i]sin cambiar nada más obviamente cambiaría la semántica del programa, pero en algunos procesadores cuando se usa un compilador sin una lógica de optimización de elevación de bucle, incrementando py quna vez y luego ejecutando un bucle que funciona, por ejemplo *(p++)=*(q++);, sería más rápido que usar un bucle que funciona *(++pp)=*(++q);. Para bucles muy ajustados en algunos procesadores, la diferencia de velocidad puede ser significativa (más del 10%), pero ese es probablemente el único caso en C donde el incremento posterior es materialmente más rápido que el incremento previo.
supercat