Declarar variables globales o dentro del loop

Buenas!

He estado buscando información acerca de la diferencia que existe entre declarar variables globales (fuera del loop) o declararlas dentro (las cuales entiendo que son locales de la función loop) y no me termino de aclarar. Entiendo que si las declaras como globales estas se guardan en el 'static data' de la SRAM (ver foto) y no se borran nunca. Mi pregunta es la siguiente:

  • ¿Las que se declaran dentro del loop donde se guardan exactamente? ¿A cada iteración del loop, se van borrando y declarando otra vez?

  • Suponiendo que estas variables se van borrando y declarando a cada iteración, ¿no es mejor declararlas como globales (ya que siempre las vas a necesitar) y que solo se declaren una vez? ¿O declararlas como static dentro del loop es "lo mismo" que declararlas como globales ya que solo se declaran una vez?

Muchas gracias!

Gracias por contestar! Si no es mucho pedir te expongo mi caso y me das tu opinión: mi proyecto consiste en un sistema de monitorización de sondas de temperatura con Arduino (ya lo tengo casi acabado y, de momento, funciona a la perfección). Este, se encarga de muestrear las sondas y almacenar los datos en una tarjeta micro SD. Por otro lado, también actúa como servidor, por tanto, se hace cargo de servir todas las peticiones entrantes de los clientes (un usuario mediante el navegador se conecta al Arduino y este le sirve los ficheros html de la página web + información sobre las sondas si este lo requiere). Mi pregunta es la siguiente:

  • La mayoría de variables que uso almacenan información de las sondas (su temperatura actual, cuando se ha dado esta, a que hora, su identificador de sonda, la temperatura máxima registrada desde que se encendió el Arduino, la mínima,...). Esta información debe estar disponible en cualquier momento, ya que no sabemos cuando un cliente que se conecta al servidor puede pedir toda esta información. ¿Donde declararías todas estas variables? Yo las he declarado como globales, ya que me interesa que se declaren una sola vez y que no se borren nunca. De aquí, la duda de si declararlas como globales o como static dentro del loop.

Las siguientes variables son globales y, tal y como te he explicado, tiene sentido que lo sean (de aquí a que no siempre el tener muchas variables globales es sinónimo de chapuza xD):

/*------------- Variables de les sondes connectades a l'Arduino --------------*/

float actualTemp[MAX_NUMBER_ON_DEV]; // Array que emmagatzemarà el darrer valor de temperatura mostrejat de cada una de les sondes connectades a l'Arduino.

char dateActualTemp[MAX_NUMBER_ON_DEV][DATE_BUF_SZ] = {0};   // Buffer per a emmagatzemar la data en què s'ha realitzat l'últim mostreig de cada sonda connectada a l'Arduino.

char hourActualTemp[MAX_NUMBER_ON_DEV][HOUR_BUF_SZ] = {0};   // Buffer per a emmagatzemar l'hora en què s'ha realitzat l'últim mostreig de cada sonda connectada a l'Arduino.

float maxTemp[MAX_NUMBER_ON_DEV];    // Array que emmagatzemarà el darrer valor màxim de temperatura mostrejat de cada una de les sondes connectades a l'Arduino.

char dateMaxTemp[MAX_NUMBER_ON_DEV][DATE_BUF_SZ] = {0};  // Buffer per a emmagatzemar la data en què s'ha donat la temperatura màxima de cada sonda connectada a l'Arduino.

char hourMaxTemp[MAX_NUMBER_ON_DEV][HOUR_BUF_SZ] = {0};  // Buffer per a emmagatzemar l'hora en què s'ha donat la temperatura màxima de cada sonda connectada a l'Arduino.

float minTemp[MAX_NUMBER_ON_DEV];    // Array que emmagatzemarà el darrer valor mínim de temperatura mostrejat de cada una de les sondes connectades a l'Arduino.

char dateMinTemp[MAX_NUMBER_ON_DEV][DATE_BUF_SZ] = {0};  // Buffer per a emmagatzemar la data en què s'ha donat la temperatura mínima de cada sonda connectada a l'Arduino.

char hourMinTemp[MAX_NUMBER_ON_DEV][HOUR_BUF_SZ] = {0};  // Buffer per a emmagatzemar l'hora en què s'ha donat la temperatura mínima de cada sonda connectada a l'Arduino.

char aliasONDevices[MAX_NUMBER_ON_DEV][7] = {0}; // Array que emmagatzemarà l'alias de cada sonda connectada a l'Arduino.

uint8_t resolutionONDevices[MAX_NUMBER_ON_DEV];  // Array que emmagatzemarà la resolució (en bits) de cada sonda connectada a l'Arduino. Valors possibles: 9, 10, 11 i 12.

unsigned long samplingIntervalONDev[MAX_NUMBER_ON_DEV]; // Array que emmagatzemarà el temps de mostreig de cada sonda connectada a l'Arduino.

uint8_t numberONDevices = 0;    // Variable que emmagatzemarà el nombre de sondes connectades a l'Arduino.



/*------- Variables de les sondes incloses al registre de temperatura --------*/

char addRegDevices[MAX_NUMBER_REG_DEV][17] = {0};    // Array que emmagatzemarà les adreces de les sondes incloses al registre de temperatura.

char aliasRegDevices[MAX_NUMBER_REG_DEV][7] = {0};   // Array que emmagatzemarà l'alias de cada sonda inclosa al registre de temperatura.

unsigned long samplingIntervalRegDev[MAX_NUMBER_REG_DEV];   // Array que emmagatzemarà el temps de mostreig de cada sonda inclosa al registre de temperatura.

char namesFiles[MAX_NUMBER_REG_DEV][5] = {0};  // Array que emmagatzemarà el nom del fitxer més recent on es guarden les temperatures de cada sonda inclosa al registre de temperatura.

uint8_t numberRegDevices = 0;   // Variable que emmagatzemarà el nombre de sondes incloses al registre de temperatura.

Muchas gracias!

La diferencia fundamental entre una variable local y una static, no es dónde se almacena, sino su accesibilidad. Ambas se almacenan en memoria global, pero una variable static no se va a poder utilizar fuera de la función donde se declaró. Si no necesitas llamarla desde otra función, no es mala opción usar static. De esa forma verás la declaración de la variable en su “ambiente de trabajo”, en lugar de en una concentración de declaraciones al principio del código. Incluso puedes tener una variable static con el mismo nombre en dos funciones diferentes, y cada una mantendrá su valor independiente entre llamadas. Quizás te ayude esta explicación.

Sí, entiendo lo que dices. En mi caso todas estas variables tienen que ser globales sí o sí, ya que, aparte de usarse en el loop, también se utilizan en otras funciones (yo mismo me puedo responder a mi pregunta, pero básicamente lo he planteado para escuchar opiniones y dejar claro que el hecho de que un código tenga muchas variables globales no significa que esté mal programado siempre que tenga sentido el hacerlas globales). Creo que, como resumen, podríamos decir que las variables se tienen que declarar dentro de su ámbito de trabajo y listos!

EDIT1: una segunda opción seria declararlas como static dentro del loop y pasarlas como parámetro a estas funciones que tienen que utilizar su valor (si no me equivoco se puede pasar el valor de una variable static como parámetro, ya que solo se está pasando su valor a la función, no la variable en si). Pero si nos centramos en la memoria SRAM utilizada, el consumo es el mismo si se declaran como static al principio del loop como si se declaran como globales.

EDIT2: una duda que se me viene a la cabeza. El siguiente ejemplo en pseudocódigo:

funcion() {
if (condicion) {
int a;
}
}

¿Cuando se sale de la condición la variable se destruye?¿O su ámbito de trabajo es la función entera? Siento preguntar estas cosas, pero, aunque parezcan obvias, aveces se olvidan...

Saludos!

No te preocupes, el Arduino hace solo lo que tiene que hacer, no trabaja de más. La página web tiene 3 pestañas: Home/Estado actual del sistema/Gráficos (cada pestaña es un archivo .html. Incluso, para que el navegador no haga peticiones de más, el código CSS, JS y HTML de cada pestaña está incluido en el mismo archivo, no en archivos separados). Cuando el navegador hace una petición de ese archivo, el Arduino recibe la petición y le envia ese archivo (los archivos los tengo guardados dentro de la targeta micro SD. Para agilizar la velocidad de transferencia de los archivos los voy pasando con un buffer de 1K (lo sé, es muy grande, pero de momento voy sobrado de memoria ya que el Mega tiene 8K de SRAM)).

Por otra parte, el Arduino va muestreando las sondas y va almacenando los datos dentro de archivos .csv contenidos en la targeta SD. Cuando el cliente accede a la pestaña Estado actual del sistema, el navegador hace una petición de la información actual del sistema (temperatura actual de cada sonda, fecha y hora en la que se ha tomado, temperatura máxima, mínima, en que hora se han dado, identificador de sonda, alias,… Esta información, por comodidad, se guarda en SRAM, ya que así es muy fácil de brindar al cliente) la cual el Arduino responde con un archivo XML contenido dentro de la respuesta HTTP. El cliente va haciendo peticiones de forma periódica para actualizar los datos que se ven en esta pestaña. También, se puede configurar una resolución y tiempo de muestreo individualizado para cada sonda (estos parámetros, para cada sonda, se guardan en un archivo .txt dentro de la targeta SD).

Si el cliente accede a la pestaña Gráficos, el navegador hace una petición al Arduino solicitándole los datos históricos de temperatura guardados en los archivos .csv. De nuevo, el Arduino monta un archivo XML contenido dentro de la respuesta HTTP con los 100 últimos datos guardados (por defecto). También, el usuario puede seleccionar, para cada sonda, de que fecha/intervalo de fecha quiere que sean los datos a visualizar.

El sistema es flexible, se le pueden ir añadiendo más sondas aún estando encendido, tiene un LED indicador sobre lo que hace el Arduino, un botón para parar/reanudar el muestreo y un largo etcétera xDDD (cuando lo termine del todo, lo voy a colgar al foro).

Volviendo al tema de memoria:

En términos de uso de memoria, no veo diferencia en declarar una variable como global o declararla como static dentro del loop y pasarla como parámetro a las funciones que la utilizan. Gastas la misma memoria.

Acabo de ejecutar el siguiente ejemplo (estaba haciendo pruebas con if’s, for’s…):

#include <MemoryFree.h>

void setup(){

	Serial.begin(9600);

	for (int count = 0; count < 1; count++) {

		Serial.print("freeMemory()=");
		Serial.println(freeMemory());

		unsigned long a[400] = {0};

		Serial.print("freeMemory()=");
		Serial.println(freeMemory());

	}

	Serial.print("freeMemory()=");
	Serial.println(freeMemory());

}

void loop(){

	Serial.print("freeMemory()=");
	Serial.println(freeMemory());

}

Salida:

freeMemory()=7976
freeMemory()=7976
freeMemory()=7976
freeMemory()=7976
freeMemory()=7976
freeMemory()=7976
....

¿Por que cuando entra al loop no se borra el array a?

EDIT: por lo que me han dicho la razón residen en el hecho de que, como esta variable no se usa, el compilador lo detecta y la optimiza y, por tanto, no acaba consumiendo SRAM.