c - ejemplo - variable global vba
¿Cuándo está bien usar una variable global en C? (15)
Considere este koan: "si el alcance es lo suficientemente estrecho, todo es global".
Todavía es muy posible en esta edad tener que escribir un programa de utilidad muy rápido para hacer un trabajo de una sola vez.
En tales casos, la energía requerida para crear un acceso seguro a las variables es mayor que la energía ahorrada por los problemas de depuración en una utilidad tan pequeña.
Este es el único caso en el que puedo pensar de forma directa donde las variables globales son sabias, y es relativamente raro. Los programas útiles y novedosos, tan pequeños que pueden mantenerse completamente dentro de la memoria a corto plazo del cerebro, son cada vez más infrecuentes, pero aún existen.
De hecho, podría afirmar audazmente que si el programa no es tan pequeño, las variables globales deberían ser ilegales.
- Si la variable nunca cambiará, entonces es una constante, no una variable.
- Si la variable requiere acceso universal, deben existir dos subrutinas para obtenerla y configurarla, y deben sincronizarse.
- Si el programa comienza pequeño y podría ser más grande más tarde, entonces codifique como si el programa fuera grande hoy y elimine las variables globales. ¡No todos los programas crecerán! (Aunque, por supuesto, eso supone que el programador está dispuesto a deshacerse del código a veces).
Aparentemente hay mucha variedad de opiniones, desde " Nunca! Siempre encapsula (incluso si es simplemente macro) " a " No es gran cosa, úsalas cuando sea más conveniente que no " .
Asi que.
Razones específicas y concretas (preferiblemente con un ejemplo)
- Por qué las variables globales son peligrosas
- Cuando se deben usar variables globales en lugar de alternativas
- Qué alternativas existen para aquellos que están tentados a usar variables globales inapropiadamente
Si bien esto es subjetivo, elegiré una respuesta (que para mí representa mejor la relación amor / odio que todo desarrollador debería tener con los globales) y la comunidad votará la suya justo debajo.
Creo que es importante que los novatos tengan este tipo de referencia, pero no la desordenen si existe otra respuesta que sea sustancialmente similar a la suya: agregue un comentario o edite la respuesta de otra persona.
-Adán
Cuando declaras constantes.
Debe considerar en qué contexto también se usará la variable global. En el futuro, querrás que este código se duplique.
Por ejemplo, si está usando un socket dentro del sistema para acceder a un recurso. En el futuro, si desea acceder a más de uno de estos recursos, si la respuesta es sí, me mantendría alejado de los globales en primer lugar, por lo que no se requerirá un refactor importante.
Es una herramienta como cualquier otra usualmente usada en exceso, pero no creo que sean malas.
Por ejemplo, tengo un programa que realmente funciona como una base de datos en línea. Los datos se almacenan en la memoria, pero otros programas pueden manipularlo. Existen rutinas internas que actúan de forma muy parecida a los procedimientos almacenados y desencadenantes en una base de datos.
Este programa tiene cientos de variables globales, pero si lo piensas, ¿qué es una base de datos sino un gran número de variables globales?
Este programa ha estado en uso durante aproximadamente diez años a través de muchas versiones y nunca ha sido un problema y lo volvería a hacer en un minuto.
Debo admitir que en este caso los vars globales son objetos que tienen métodos usados para cambiar el estado del objeto. Así que rastrear quién cambió el objeto durante la depuración no es un problema ya que siempre puedo establecer un punto de interrupción en la rutina que cambia el estado del objeto. O incluso más simple, simplemente enciendo el registro integrado que registra los cambios.
Estoy en el campamento "nunca" aquí; si necesita una variable global, al menos use un patrón singleton . De esta forma, obtendrá los beneficios de la creación de instancias perezosas y no saturará el espacio de nombres global.
La única forma en que puede hacer que las variables globales funcionen es darles nombres que aseguren que son únicas.
Ese nombre generalmente tiene un prefijo asociado a algún "módulo" o conjunto de funciones para las cuales la variable global está particularmente enfocada o es significativa.
Esto significa que la variable "pertenece" a esas funciones, es parte de ellas. De hecho, lo global generalmente se puede "envolver" con una pequeña función que acompaña a las otras funciones, en el mismo archivo .h
el mismo prefijo.
Prima.
Cuando haces eso, de repente, ya no es realmente global. Ahora es parte de algún módulo de funciones relacionadas.
Esto siempre se puede hacer. Con un poco de pensamiento, todas las variables anteriormente globales se pueden asignar a una colección de funciones, asignadas a un archivo .h
específico y aisladas con funciones que le permiten cambiar la variable sin romper nada.
En lugar de decir "nunca usar variables globales", puede decir "asignar las responsabilidades de la variable global a algún módulo donde tenga más sentido".
La complejidad del código no es la única optimización de preocupación. Para muchas aplicaciones, la optimización del rendimiento tiene una prioridad mucho mayor. Pero, lo que es más importante, el uso de variables globales puede REDUCIR drásticamente la complejidad del código en muchas situaciones. Hay muchas situaciones, tal vez especializadas, en las que las variables globales no son solo una solución aceptable, sino preferida. Mi ejemplo especializado favorito es su uso para proporcionar comunicación entre el hilo principal de una aplicación con una función de devolución de llamada de audio que se ejecuta en un hilo en tiempo real.
Es engañoso sugerir que las variables globales son una responsabilidad en las aplicaciones de subprocesos múltiples, ya que CUALQUIER variable, independientemente del alcance, es una responsabilidad potencial si está expuesta a cambios en más de un hilo.
Use las variables globales con moderación. Las estructuras de datos se deben usar siempre que sea posible para organizar y aislar el uso del espacio de nombres global.
El alcance variable ofrece a los programadores una protección muy útil, pero puede tener un costo. Esta noche escribí sobre variables globales porque soy un experimentado programador de Objective-C que a menudo se frustra con las barreras que los lugares de orientación al objeto tienen sobre el acceso a los datos. Yo argumentaría que el fanatismo antiglobal proviene principalmente de programadores más jóvenes y teóricos experimentados principalmente con API orientadas a objetos aisladas sin una experiencia profunda y práctica de las API de nivel de sistema y su interacción en el desarrollo de aplicaciones. Pero tengo que admitir que me siento frustrado cuando los vendedores usan el espacio de nombres de manera descuidada. Varias distribuciones de Linux tenían "PI" y "TWOPI" predefinidas globalmente, por ejemplo, lo que rompió gran parte de mi código personal.
Las constantes globales son útiles: obtienes más seguridad de tipo que las macros de preprocesador y aún así es tan fácil cambiar el valor si decides que lo necesitas.
Las variables globales tienen algunos usos, por ejemplo, si la operación de muchas partes de un programa depende de un estado particular en la máquina de estado. Siempre que limite el número de lugares que pueden MODIFICAR la variable que rastrea los errores que lo involucran no es tan malo.
Las variables globales se vuelven peligrosas casi tan pronto como creas más de un hilo. En ese caso, debería limitar el alcance a (como máximo) un archivo global (al declararlo estático) variable y métodos getter / setter que lo protegen del acceso múltiple donde podría ser peligroso.
Las variables globales en C son útiles para hacer que el código sea más legible si varios métodos requieren una variable (en lugar de pasar la variable a cada método). Sin embargo, son peligrosos porque todas las ubicaciones tienen la capacidad de modificar esa variable, lo que hace que sea potencialmente difícil rastrear errores. Si debe usar una variable global, asegúrese siempre de que solo se modifique directamente mediante un método y haga que todos los que llaman usen ese método. Esto facilitará la depuración de problemas relacionados con los cambios en esa variable.
Las variables globales se deben usar cuando múltiples funciones necesitan acceder a los datos o escribir en un objeto. Por ejemplo, si debe pasar datos o una referencia a varias funciones, como un único archivo de registro, un grupo de conexiones o una referencia de hardware a la que se debe acceder a través de la aplicación. Esto evita declaraciones de funciones muy largas y grandes asignaciones de datos duplicados.
Por lo general, no debe usar variables globales a menos que sea absolutamente necesario porque las variables globales solo se limpian cuando se le indica expresamente que lo haga o su programa finaliza. Si está ejecutando una aplicación multiproceso, varias funciones pueden escribir en la variable al mismo tiempo. Si tiene un error, rastrear ese error puede ser más difícil porque no sabe qué función está cambiando la variable. También se encuentra con el problema de nombrar conflictos a menos que use una convención de nomenclatura que explícitamente le dé a las variables globales un nombre único.
Las variables siempre deben tener el alcance más pequeño posible. El argumento detrás de eso es que cada vez que aumenta el alcance, tiene más código que potencialmente modifica la variable, por lo tanto, se induce más complejidad en la solución.
Por lo tanto, es claro que se prefiere evitar el uso de variables globales si el diseño y la implementación lo permiten de forma natural. Debido a esto, prefiero no usar variables globales a menos que sean realmente necesarias.
No puedo estar de acuerdo con la afirmación "nunca". Al igual que cualquier otro concepto, las variables globales son una herramienta que se debe usar cuando sea necesario. Prefiero usar variables globales que usar algunas construcciones artificiales (como pasar punteros) que solo enmascararían la intención real. Buenos ejemplos en los que se usan variables globales son las implementaciones de patrones únicos o el acceso de registro en sistemas integrados.
Sobre cómo detectar realmente usos excesivos de variables globales: inspección, inspección, inspección. Cada vez que veo una variable global, me tengo que preguntar a mí mismo: ¿Eso es REALMENTE necesario en un ámbito global?
Puedo pensar en varias razones:
depuración / prueba (advertencia: no se ha probado este código):
#include <stdio.h>
#define MAX_INPUT 46
int runs=0;
int fib1(int n){
++runs;
return n>2?fib1(n-1)+fib1(n-2):1;
};
int fib2(int n,int *cache,int *len){
++runs;
if(n<=2){
if(*len==2)
return 1;
*len=2;
return cache[0]=cache[1]=1;
}else if(*len>=n)
return cache[n-1];
else{
if(*len!=n-1)
fib2(n-1,cache,len);
*len=n;
return cache[n-1]=cache[n-2]+cache[n-3];
};
};
int main(){
int n;
int cache[MAX_INPUT];
int len=0;
scanf("%i",&n);
if(!n||n>MAX_INPUT)
return 0;
printf("fib1(%i)==%i",n,fib1(n));
printf(", %i run(s)/n",runs);
runs=0;
printf("fib2(%i)==%i",n,fib2(n,&cache,&len));
printf(", %i run(s)/n",runs);
main();
};
Utilicé variables de ámbito para fib2, pero ese es otro escenario donde los globales podrían ser útiles (funciones matemáticas puras que necesitan almacenar datos para evitar tomar para siempre).
programas utilizados solo una vez (por ejemplo, para un concurso), o cuando el tiempo de desarrollo debe acortarse
los globales son útiles como constantes tipadas, donde una función en algún lugar requiere * int en lugar de int.
Generalmente evito los globales si pretendo usar el programa por más de un día.
Vine del campo "nunca", hasta que comencé a trabajar en la industria de la defensa. Existen algunos estándares de la industria que requieren que el software use variables globales en lugar de memoria dinámica (malloc en el caso C). Tengo que repensar mi enfoque de la asignación de memoria dinámica para algunos de los proyectos en los que trabajo. Si puede proteger la memoria "global" con los semáforos, hilos, etc. apropiados, esto puede ser un enfoque aceptable para la gestión de su memoria.
Cuando no está preocupado por el código seguro para subprocesos : úselos donde sea que tenga sentido, en otras palabras, donde tenga sentido expresar algo como un estado global.
Cuando su código puede ser de subprocesos múltiples : evite a toda costa. Resuma variables globales en colas de trabajo o alguna otra estructura segura para subprocesos, o si es absolutamente necesario, envuélvalas en bloqueos, teniendo en cuenta que estos son probablemente cuellos de botella en el programa.
- Cuándo no utilizar: las variables globales son peligrosas porque la única forma de saber cómo cambió la variable global es rastrear el código fuente completo dentro del archivo .c dentro del cual están declaradas (o, todos los archivos .c si es externo como bien). Si su código presenta errores, debe buscar su (s) archivo (s) fuente (s) completo (s) para ver qué funciones lo cambian y cuándo. Es una pesadilla para depurar cuando sale mal. A menudo damos por descontado el ingenio detrás del concepto de variables locales saliendo airosamente del alcance: es fácil rastrear
- Cuándo se debe utilizar: las variables globales se deben usar cuando su utilización no está excesivamente enmascarada y cuando el costo de usar variables locales es excesivamente complejo hasta el punto en que compromete la legibilidad. Con esto, me refiero a la necesidad de tener que agregar un parámetro adicional a los argumentos de la función y retorna y pasa punteros, entre otras cosas. Tres ejemplos clásicos: cuando uso pop y push stack, esto se comparte entre funciones. Por supuesto, podría usar variables locales, pero luego tendría que pasar punteros como un parámetro adicional. El segundo ejemplo clásico se puede encontrar en "The C Programming Language" de K & R, donde definen las funciones getch () y ungetch () que comparten una matriz de búfer de caracteres global. Una vez más, no es necesario que sea global, pero ¿vale la pena la complejidad añadida cuando es bastante difícil estropear el uso del buffer? El tercer ejemplo es algo que encontrarás en el espacio incrustado entre los aficionados a Arduino. Muchas funciones dentro de la función de bucle principal comparten la función millis () que es el instante instantáneo de cuando se invoca la función. Como la velocidad del reloj no es infinita, los milis () se diferenciarán en un solo bucle. Para hacerlo constante, tome una instantánea del tiempo anterior a cada ciclo y guárdelo en una variable global. La instantánea de tiempo ahora será la misma que cuando se accede por las muchas funciones.
- Alternativas: No mucho. Limítese al alcance local tanto como sea posible, especialmente al comienzo del proyecto, y no al revés. A medida que crezca el proyecto y considere que la complejidad se puede reducir utilizando variables globales, hágalo, pero solo si cumple con los requisitos del punto dos. Y recuerde, utilizar el alcance local y tener un código más complicado es el mal menor en comparación con el uso irresponsable de variables globales.