2012-09-23 50 views
6

Siempre he tenido la impresión de que no debería definir una variable dentro de un ciclo porque es innecesario o derrochador. Esto hace que me pregunte si la siguiente función recv() necesita un tampón fresco para cada iteración del bucle:¿Por qué se define este búfer dentro de un bucle?

while (totalBytesRecvd < echoStrLen) 
{ 
    char buffer[BUFSIZE]; 
    numBytes = recv(sock, buffer, BUFSIZE - 1, 0); 
    ... 
    totalBytesRecvd += numBytes; 
    buffer[numBytes] = '\0'; 
    fputs(buffer, stdout); 
} 

La documentación para recv() no menciona nada acerca de cómo se utiliza el puntero de memoria intermedia. Para una mejor comprensión, traté de definir el búfer justo antes del bucle, y recv() parece sobrescribir el búfer, en lugar de redefinirlo. Lo cual tiene sentido ya que recv() pasa un puntero al principio del búfer.

¿Hay alguna razón específica para definir un búfer una y otra vez dentro de un bucle? ¿O es mi entendimiento básico de esto correcto?

Respuesta

8

recv, como read y otras funciones similares, no se preocupa por el contenido anterior del búfer, solo lo usa para escribir el resultado.

No es que marque la diferencia de todos modos: dado que no está inicializando su búfer, su contenido será "indefinido" incluso si declara la variable como local en el bucle.

Además, en la mayoría de las implementaciones de C:

  • no inicializar variables que los medios que se llevarán a cualquier cosa que esté en la pila en ese lugar, que a su vez significa que se va a tomar la misma ubicación que estaba en la iteración anterior, efectivamente le da exactamente el mismo resultado que tener la variable fuera del ciclo.
  • las asignaciones de pila son baratas; en general, solo requieren ajustar un registro;
  • En realidad, son incluso más baratos: por lo general, el ajuste de registro se realiza justo al comienzo de la función, teniendo en cuenta todas las variables locales; el alcance de una variable local se convierte simplemente en una construcción en tiempo de compilación, ya que se asigna cuando se inicia la función.

Obviamente, en cambio, si inicializado la variable que sería diferente - el código para realizar la inicialización tendría que ejecutar en cada iteración; pero, como se dijo anteriormente, no hay necesidad de inicializar nada, recv simplemente no le importa el estado actual del búfer.

+0

+1, mucho mejor que mi respuesta. – Martin

+0

Todas las respuestas muy útiles (y similares) hasta el momento. ¿Alguien puede señalarme su origen? ¿O puedo encontrar todo esto en mi documentación del compilador? La optimización del compilador se pasó por alto en el libro de programación C que leí. – Nocturno

+2

Mi fuente es demasiado tiempo dedicado a mirar el ensamblador generado por los compiladores :). En general, no se preocupe por este tipo de optimización. Use los algoritmos correctos para el trabajo correcto, y solo considere estos tipos de ajustes si puede demostrar una pieza de código * necesita * optimización. – Martin

2

Declarar una variable dentro de un bucle solo reserva espacio de pila para ello; no borrará el contenido ni tocará la variable. Por lo tanto, este estilo de declaración no es más costoso que declararlo fuera del ciclo.

5

No es derrochador. Declara el alcance de esta variable. El compilador puede reclamar el espacio en la pila para otros fines sin asignar más de la pila fuera de este alcance. No requiere gastos adicionales en tiempo de ejecución: el compilador calcula el espacio de pila necesario en tiempo de compilación y ajusta el puntero de pila solo una vez al comienzo de la función.

2

Definición de una variable en un bucle es sólo es malo si es caro de construir, y eso es raramente el caso en C.

Con incluso el más básico de la optimización, no es ni siquiera va a molestar modificar el puntero de pila de cada iteración del ciclo Muchos compiladores inicializarán en cero una matriz en modo de depuración, pero a menos que este búfer sea enorme, no es probable que sea un gran problema.

En C++, puede pensar en no declarar una variable con un constructor costoso si puede salirse con la suya construyéndola una vez fuera del ciclo, pero eso no va a ser un problema aquí.

1

Siempre he tenido la impresión de que no debería definir una variable dentro de un bucle porque es innecesario o derrochador.

Siempre estás estado bajo una impresión incorrecta, y uno que no sólo carece de fundamento, pero enfrenta una muy mala práctica - la optimización prematura - contra uno muy bueno, la declaración de variables como cerca de su uso como posible.

1

También solía pensar que mover declaraciones fuera de bucles daría como resultado un código más rápido, especialmente para estructuras más grandes como matrices. Creo que esto es a menudo cierto con los datos malloc'd (montón), porque puede desperdiciar mucho en sobrecarga llamando a malloc y libre dentro del ciclo. Para la pila de datos (como la tuya) no creo que sea un gran problema.

Sin embargo, recientemente me encontré con la situación opuesta, donde moví una declaración de un bucle interno y en realidad terminé con el código más lento. Se me ocurrió con algunas posibles explicaciones para esto:

  1. Cuando la declaración se trasladó al ámbito más amplio que el compilador no era capaz de optimizar el código de la manera más eficaz.
  2. Se guardó una mayor cantidad de datos en la memoria entre iteraciones de bucles, lo que produjo un uso ineficiente de la memoria caché.

De todos modos, no tengo una buena referencia para esto, pero mover las definiciones dentro o fuera de los bucles puede hacer que el código sea más rápido o más lento según la situación. Tienes que medir el rendimiento antes y después de cambiar el código para ver si hay una diferencia.

+0

'También solía pensar que mover las declaraciones fuera de los bucles daría como resultado un código más rápido, especialmente para estructuras más grandes como arreglos.' -- *¿Por qué pensaste eso? "Creo que esto es a menudo cierto con los datos malloc (datos)". ¡La asignación no es una declaración! Si tuviera un enunciado como 'int foo = very_long_calculation (rand());', por supuesto, sería costoso mover el * calculation * dentro de un bucle. ¿Cómo es una llamada a malloc diferente? –

Cuestiones relacionadas