Uso de variables globales en sistemas integrados

15

Comencé a escribir firmware para mi producto y soy un novato aquí. Revisé muchos artículos sobre no usar variables o funciones globales. ¿Hay algún límite para usar variables globales en un sistema de 8 bits o es un 'No-No' completo? ¿Cómo debo usar las variables globales en mi sistema o debo evitarlas por completo?

Me gustaría recibir valiosos consejos de ustedes sobre este tema para que mi firmware sea más compacto.

    
pregunta Rookie91

6 respuestas

30

Puedes usar variables globales con éxito, siempre y cuando tengas en cuenta las pautas de @ Phil. Sin embargo, aquí hay algunas formas agradables de evitar sus problemas sin hacer que el código compilado sea menos compacto.

  1. Use variables estáticas locales para el estado persistente al que solo desea acceder dentro de una función.

    #include <stdint.h>
    void skipper()
    {
        static uint8_t skip_initial_cycles = 5;
        if (skip_initial_cycles > 0) {
            skip_initial_cycles -= 1;
            return;
        }
        /* ... */
    }
    
  2. Use una estructura para mantener juntas las variables relacionadas, para que quede más claro dónde deberían estar utilizado y donde no.

    struct machine_state {
         uint8_t level;
         uint8_t error_code;
    } machine_state;
    
    struct led_state {
        uint8_t red;
        uint8_t green;
        uint8_t blue;
    } led_state;
    
    void machine_change_state()
    {
        machine_state.level += 1;
        /* ... */
        /* We can easily remember not to use led_state in this function. */
    }
    
    void machine_set_io()
    {
        switch (machine_state.level) {
        case 1:
            PIN_MACHINE_IO_A = 1;
            /* ... */
        }
    }
    
  3. Use variables estáticas globales para hacer que las variables sean visibles solo dentro del archivo C actual. Esto evita el acceso accidental por código en otros archivos debido a conflictos de nombres.

    /* time_machine.c */
    static uint8_t current_time;
    /* ... */
    
    /* delay.c */
    static uint8_t current_time; /* A completely separate variable for this C file only. */
    /* ... */
    

Como nota final, si está modificando una variable global dentro de una rutina de interrupción y la está leyendo en otro lugar:

  • Marque la variable volatile .
  • Asegúrese de que sea atómico para la CPU (es decir, de 8 bits para una CPU de 8 bits).

O

  • Use un mecanismo de bloqueo para proteger el acceso a la variable.
respondido por el richarddonkin
24

Las razones por las que no querría usar variables globales en un sistema de 8 bits son las mismas que no querría usarlas en cualquier otro sistema: dificultan el razonamiento sobre el comportamiento del programa.

Solo los programadores malos se atascan en reglas como "no usar variables globales". Los buenos programadores entienden la razón detrás de las reglas, luego tratan las reglas más como pautas.

¿Es tu programa fácil de entender? ¿Es predecible su comportamiento? ¿Es fácil modificar partes de él sin romper otras partes? Si la respuesta a cada una de estas preguntas es , entonces estás en camino a un buen programa.

    
respondido por el Phil Frost
5

No debes evitar por completo el uso de variables globales ("globales" para abreviar). Pero, debes usarlos juiciosamente. Los problemas prácticos con el uso excesivo de globales:

  • Los globales son visibles en toda la unidad de compilación. Cualquier código en la unidad de compilación puede modificar un global. Las consecuencias de una modificación pueden surgir en cualquier lugar donde se evalúe este global.
  • Como resultado, los globales hacen que el código sea más difícil de leer y entender. El programador siempre debe tener en cuenta todos los lugares donde se evalúa y asigna el global.
  • El uso excesivo de elementos globales hace que el código sea más propenso a defectos.

Es una buena práctica agregar un prefijo g_ al nombre de las variables globales. Por ejemplo, g_iFlags . Cuando ve la variable con el prefijo en el código, inmediatamente reconoce que es un global.

    
respondido por el Nick Alexeev
4

La ventaja de las estructuras de datos globales en el trabajo integrado es que son estáticas. Si todas las variables que necesita son globales, nunca se quedará sin memoria accidentalmente cuando se ingresen las funciones y se haga espacio para ellas en la pila. Pero entonces, en ese punto ¿por qué tienen funciones? ¿Por qué no una función grande que maneje toda la lógica y los procesos, como un programa BASIC sin GOSUB permitido? Si toma esta idea lo suficiente, tendrá un programa típico de lenguaje ensamblador de los años 70. Eficiente, e imposible de mantener y solucionar problemas.

Entonces, use globalmente con criterio, como variables de estado (por ejemplo, si cada función necesita saber si el sistema está en estado de interpretación o ejecución) y otras estructuras de datos que deben ser vistas por muchas funciones y como dice @PhilFrost, es ¿El comportamiento de tus funciones predecible? ¿Existe la posibilidad de llenar la pila con una cadena de entrada que nunca termina? Estos son asuntos para el diseño de algoritmos.

Tenga en cuenta que la estática tiene un significado diferente dentro y fuera de una función. enlace

enlace

    
respondido por el C. Towne Springer
4

Las variables globales solo deben usarse para un estado verdaderamente global. Usando una variable global para representar algo como, por ejemplo, la latitud del límite norte del mapa solo funcionará si solo puede haber un "límite norte del mapa". Si en el futuro es posible que el código tenga que trabajar con varios mapas que tienen diferentes límites del norte, es probable que el código que usa una variable global para el límite del norte deba ser revisado.

En las aplicaciones informáticas típicas, a menudo no hay una razón particular para suponer que nunca habrá más de una cosa. Sin embargo, en los sistemas integrados, tales suposiciones son a menudo mucho más razonables. Si bien es posible que se solicite a un programa informático típico que admita múltiples usuarios simultáneos, la interfaz de usuario de un sistema integrado típico se diseñará para que un solo usuario interactúe con sus botones y su pantalla. Como tal, en cualquier momento tendrá un solo estado de interfaz de usuario. Diseñar el sistema de modo que múltiples usuarios puedan interactuar con múltiples teclados y pantallas requeriría mucha más complejidad y demoraría mucho más en implementarse que el diseño para un solo usuario. Si nunca se solicita al sistema que admita a múltiples usuarios, se desperdiciará cualquier esfuerzo adicional invertido para facilitar dicho uso. A menos que sea probable que se requiera soporte multiusuario, sería más prudente correr el riesgo de tener que descartar el código usado para una interfaz de usuario único en el caso de que se requiera soporte multiusuario, que pasar más tiempo agregando multiusuario. soporte al usuario que probablemente nunca será necesario.

Un factor relacionado con los sistemas integrados es que, en muchos casos (especialmente en lo que se refiere a interfaces de usuario), la única forma práctica de admitir que haya más de uno sería utilizar múltiples subprocesos. En ausencia de alguna otra necesidad de subprocesos múltiples, es probable que sea mejor usar un diseño simple de un solo subproceso que aumentar la complejidad del sistema con subprocesos múltiples que probablemente nunca sean realmente necesarios. De todos modos, si agregar más de uno de ellos requeriría un gran rediseño del sistema, no importará si también requiere volver a trabajar el uso de algunas variables globales.

    
respondido por el supercat
-1

Mucha gente está confundida sobre este tema. La definición de una variable global es:

  

Algo que es accesible desde cualquier parte de tu programa.

Esto no es lo mismo que las variables de alcance de archivo , que se declaran con la palabra clave static . Esas son variables globales no , son variables privadas locales.

 int x; // global variable
 static int y; // file scope variable

 void some_func (void) {...} // added to demonstrate that the variables above are at file scope.

¿Deberías usar variables globales? Hay algunos casos en los que está bien:

En todos los demás casos, nunca deberá utilizar variables globales. Nunca hay una razón para hacerlo. En su lugar, utilice variables de alcance de archivo , lo cual está perfectamente bien.

Debe esforzarse por escribir módulos de código independientes y autónomos diseñados para realizar una tarea específica. Dentro de esos módulos, las variables de alcance del archivo interno deben residir como miembros de datos privados. Este método de diseño se conoce como orientación a objetos y es ampliamente reconocido como un buen diseño.

    
respondido por el Lundin

Lea otras preguntas en las etiquetas