Un bloque es una lista de declaraciones que se ejecutarán. Ejemplos de dónde aparecen los bloques en C son después de una declaración while y en declaraciones if
while( boolean expression)
statement OR block
if (boolean expression)
statement OR block
C también permite que un bloque se anide en un bloque. Puedo usar esto para reutilizar nombres de variables, supongamos que realmente me gusta 'x'
int x = 0;
while (x < 10)
{
{
int x = 5;
printf("%d",x)
}
x = x+1;
}
imprimirá el número 5 diez veces. Supongo que podría ver situaciones en las que es deseable mantener bajo el número de nombres de variables. Quizás en macro expansión. Sin embargo, no puedo ver ninguna razón difícil para necesitar esta función. ¿Alguien puede ayudarme a comprender los usos de esta función al proporcionar algunas expresiones idiomáticas donde se usa?
Respuestas:
La idea no es mantener baja la cantidad de nombres de variables o alentar la reutilización de nombres, sino limitar el alcance de las variables. Si usted tiene:
entonces el alcance de
y
se limita al bloque, lo que significa que puede olvidarse antes o después del bloque. Verá que esto se usa con mayor frecuencia en relación con bucles y condicionales. También lo ve más a menudo en lenguajes tipo C como C ++, donde una variable que está fuera de alcance causa su destrucción.fuente
Porque en los viejos tiempos de C las nuevas variables solo podían declararse en un nuevo bloque.
De esta forma, los programadores podrían introducir nuevas variables en el medio de una función sin filtrarla y minimizar el uso de la pila.
Con los optimizadores de hoy es inútil y una señal de que debe considerar extraer el bloque en su propia función.
En una declaración de cambio, es útil encerrar los casos en sus propios bloques para evitar la doble declaración.
En C ++ es muy útil, por ejemplo, para los protectores de bloqueo RAII y para garantizar que los destructores ejecuten el bloqueo de liberación cuando la ejecución se salga del alcance y sigan haciendo otras cosas fuera de la sección crítica.
fuente
No lo vería como bloques "arbitrarios". No es una característica que signifique tanto para el uso del desarrollador, pero la forma en que C usa bloques permite usar la misma construcción de bloque en varios lugares con la misma semántica. Un bloque (en C) es un nuevo alcance, y las variables que lo dejan se eliminan. Esto es uniforme independientemente de cómo se use el bloque.
En otros idiomas, este no es el caso. Esto tiene la ventaja de permitir menos abuso como muestra, pero la desventaja de que los bloques se comportan de manera diferente dependiendo del contexto en el que se encuentren.
Raramente he visto bloques independientes utilizados en C o C ++, a menudo cuando hay una estructura grande o un objeto que representa una conexión o algo de lo que desea forzar la destrucción. Por lo general, esto es una pista de que su función está haciendo demasiadas cosas y / o es demasiado larga.
fuente
Tienes que darte cuenta, los principios de programación que parecen obvios ahora no siempre fueron así. Las mejores prácticas de C dependen en gran medida de la antigüedad de sus ejemplos. Cuando se introdujo C por primera vez, se consideraba demasiado ineficiente dividir el código en funciones pequeñas. Dennis Ritchie básicamente mintió y dijo que las llamadas a funciones eran realmente eficientes en C (no lo eran en ese momento), que fue lo que hizo que la gente comenzara a usarlas más, aunque de alguna manera los programadores de C nunca pasaron por completo una cultura de optimización prematura.
Que es una buena práctica de programación aún hoy en día para limitar el alcance de las variables de lo más pequeño posible. Hoy en día, generalmente lo hacemos creando una nueva función, pero si las funciones se consideran costosas, la introducción de un nuevo bloque es una forma lógica de limitar su alcance sin la sobrecarga de una llamada a la función.
Sin embargo, comencé a programar en C hace más de 20 años, cuando tenía que declarar todas sus variables en la parte superior de un alcance, y no recuerdo que el sombreado de variables como ese haya sido considerado un buen estilo. Redeclarando en dos bloques, uno tras otro, como en una declaración de cambio, sí, pero sin sombrear. Tal vez si la variable ya se usó y el nombre específico era muy idiomático para la API a la que está llamando, como
dest
ysrc
enstrcpy
, por ejemplo.fuente
Los bloques arbitrarios son útiles para introducir variables intermedias que solo se usan en casos especiales de un cálculo.
Este es un patrón común en la informática científica, donde los procedimientos numéricos suelen:
Debido al segundo punto, es útil introducir variables temporales de alcance limitado, que se logran usando un bloque arbitrario o introduciendo una función auxiliar.
Si bien la introducción de una función auxiliar puede parecer una obviedad o una mejor práctica a seguir ciegamente, en realidad hay pocos beneficios para hacerlo en esta situación particular.
Debido a que hay muchos parámetros y cantidades intermedias, queremos introducir una estructura para pasarlos a la función auxiliar.
Pero, dado que queremos ser consecuentes con nuestras prácticas, no introduciremos solo una función auxiliar sino varias. Entonces, si introducimos estructuras ad-hoc que transmiten parámetros para cada función, que introducen una gran cantidad de sobrecarga de código para mover los parámetros de un lado a otro, o si introducimos uno, los regirá a todos la estructura de la hoja de trabajo, que contiene todas nuestras variables pero parece un paquete de bits sin consistencia, donde en cualquier momento solo la mitad de los parámetros tienen un significado interesante.
Por lo tanto, estas estructuras auxiliares son típicamente engorrosas y usarlas significa elegir entre hinchar código o introducir una abstracción cuyo alcance es demasiado amplio y debilitar el significado del programa, en lugar de fortalecerlo .
La introducción de funciones auxiliares podría facilitar las pruebas unitarias del programa mediante la introducción de una granularidad de prueba más fina, pero la combinación de las pruebas unitarias para los procedimientos de bajo nivel y las pruebas de regresión en forma de comparaciones (con numdiff) de trazas numéricas de los procedimientos hace un trabajo igualmente bueno .
fuente
En general, la reutilización de nombres de variables de esta manera causa demasiada confusión a los futuros lectores de su código. Es mejor simplemente nombrar la variable interior como otra cosa. De hecho, el lenguaje C # específicamente prohíbe el uso de variables de esta manera.
Pude ver cómo el uso de bloques anidados en expansiones de macro sería útil para evitar colisiones de nombres variables.
fuente
Es para determinar cosas que normalmente no tienen alcance a ese nivel. Esto es extremadamente raro, y en general la refactorización es una mejor opción, pero me he encontrado con una o dos veces en el pasado en declaraciones de cambio:
Cuando considere el mantenimiento, la refactorización de estos debe equilibrarse con tener todas las implementaciones en una fila, siempre que cada una tenga solo un par de líneas. Puede ser más fácil tenerlos todos juntos, en lugar de una lista de nombres de funciones.
En mi caso, si recuerdo correctamente, la mayoría de los casos fueron ligeras variaciones del mismo código, excepto que uno de ellos era idéntico al otro, solo que con un preprocesamiento adicional. Un modificador terminó siendo la forma más simple de tomar el código, y el alcance adicional permitía el uso de variables locales adicionales de las que no tenía que preocuparse (y los nombres de variables que se superponían accidentalmente con uno definido antes del modificador, pero usado más tarde).
Tenga en cuenta que la declaración de cambio es simplemente el uso que he encontrado. Estoy seguro de que también se puede aplicar en otros lugares, pero no recuerdo haberlos visto efectivamente utilizados de esa manera.
fuente