Para qué sirve un enum?

Muy buenas he estado trabajando en un proyecto en el cual debo hacer declaraciones de muchas variables, cuando presenté el código un ing de sistemas me dijo que por qué mejor no utilizaba los enum para un mejor entendimiento del código ya que él no tiene experiencia con Arduino, me puse a investigar acerca de esta función y la verdad es que no logro comprender aún su funcionalidad ya que cuando declaran un enum, dentro de ella se encuentran otras variables el cual vienen siendo los estados de dicha variable, ok hasta ahí vamos bien pero el problema radica en que luego se declara otra variable del tipo enum y se le asigna un valor de ese enum para luego comprarla. Entonces yo me pregunto para qué sirve este enum si de todos modos debo declarar otra variable que contenga lo que tiene el enum?

Acá dejo el código que he visto y es prácticamente el mismo que veo en todas las páginas que he buscado.

// Declaramos la enumeración que nos indica el estado del PH
enum EstadoPH {
desconocido,
reposo,
activo,
error
};
// Declaramos una variable que almacenará el estado del PH
EstadoPH dispositivoph;
void setup(){
// Inicializamos la variable
dispositivoph = desconocido;
}
void loop() {
// Comprobamos el estado del dispositivo de PH
if(dispositivoph == desconocido)
{
// Cambiamos el estado del dispositivo de PH
dispositivoph = activo;
}
}

Saludos y muchas gracias.

Según lo entiendo yo, con enum puedes crear un conjunto de variables con valores predefinidos, es decir que el valor de esas variables no tiene por qué ser true, false, un entero, long, etc sino lo que tu quieras...por ejemplo no podrías crear una variable que sea: var dia = domingo, si previamente no has creado la variable domingo ya que arduino no sabe qué es "domingo", pero con enum si puedes hacerlo...asignas un valor que no tiene que estar declarado

En principio el enum es una herramienta que nos proporciona el C++ para ayudarnos a detectar posibles errores en el código. Se recomienda no usar valores “anónimos” como 0, 1, 2, 3, 4… para ciertas cosas. Por ejemplo, si tenemos dos variables en la que almacenamos un número que nos indica el estado de dos cosas que estamos controlando, de forma arbitraria podemos asignar diferentes valores para representar diferentes estados.

Supongamos que esas dos variables son estadoAlarma y estadoAlertaSonora (los nombres de las variables deberían de ser descriptivos y no cosas como variable a y variable b). Decidimos que la variable estadoAlarma valdrá 0 para indicar que está desconectada, 1 para conectada y 2 para indicar que ha saltado. Mientras que la variable estadoAlertaSonora valdrá 0 cuando está en silencia y 1 para cuando está sonando.

Un trozo de código del programa podría quedar algo tal que así:

    if (estadoAlarma == 0 || estadoAlarma == 1) {
        estadoAlertaSonora = 0;
    }
    if (estadoAlarma == 2) {
        estadoAlertaSonora = 1;
    }

¿A alguien le parece legible este código? ¿O quedaría más legible este otro?

    if (estadoAlarma == ESTADO_ALARMA_DESCONECTADA || estadoAlarma == ESTADO_ALARMA_CONECTADA) {
        estadoAlertaSonora = ESTADO_ALERTA_SILENCIO;
    }
    if (estadoAlarma == ESTADO_ALARMA_SONANDO) {
        estadoAlertaSonora = ESTADO_ALERTA_SONANDO;
    }

Para “hacer el código más legible” habría que definir de alguna forma las constantes (esas cosas escritas todas en mayúsculas por seguir la tradición de escribirlas así para diferenciarlas de las variables). Hay tres formas básicas de definir las constantes, con el #define:

#define ESTADO_ALARMA_DESCONECTADA   0
#define ESTADO_ALARMA_CONECTADA      1
#define ESTADO_ALARMA_SONANDO        2

#define ESTADO_ALERTA_SILENCIO       0
#define ESTADO_ALERTA_SONANDO        1

int estadoAlarma = ESTADO_ALARMA_DESCONECTADA;
int estadoAlertaSonora = ESTADO_ALERTA_SILENCIO;

El problema del #define es que no tiene tipo alguno, así que aveces es preferible ponerle tipo y para ello se emplea la otra posible opción, el const:

const int ESTADO_ALARMA_DESCONECTADA = 0;
const int ESTADO_ALARMA_CONECTADA    = 1;
const int ESTADO_ALARMA_SONANDO      = 2;

const int ESTADO_ALERTA_SILENCIO     = 0;
const int ESTADO_ALERTA_SONANDO      = 1;

int estadoAlarma = ESTADO_ALARMA_DESCONECTADA;
int estadoAlertaSonora = ESTADO_ALERTA_SILENCIO;

Ojo, que estamos definiendo una constante y no una variable. Esto quiere decir dos cosas. Una es que no le podemos cambiar el valor y la otra es que no “gasta” memoria RAM (siempre que sea un tipo simple y no sea un array o una cadena).

Pero aún así hemos definido unas constantes que simplemente son de tipo int, sin más. Con los enum podemos ir un poco más lejos.

Los enum a partir del C++11 son muy potentes, pero me temo que en las diferentes versiones de los entornos de Arduino no es habitual que se usen las especificaciones del C++11, sino anteriores, así que nos conformaremos con “lo básico” de los enum y dependiendo del compilador y de cómo esté configurado nos “protegerá” más o menos de los despistes.

Lo digo porque si definimos las constantes (sí, constantes) como enumerados (enum), éstas tienen la posibilidad de “ser diferentes” las unas de las otras. Aunque básicamente siguen siento de tipo int (a partir del C++11 se le puede indicar otro tipo diferente), no sólo son de ese tipo, sino que son “algo más”.

Para ello no sólo definimos dos tipos de enumerado, sino que también los usaremos para indicar que las dos variables ya no son de tipo int sino del tipo que se ha definido para cada una de ellas (cada uno el suyo).

enum TipoEstadoAlarma {
    ESTADO_ALARMA_DESCONECTADA,
    ESTADO_ALARMA_CONECTADA,   
    ESTADO_ALARMA_SONANDO      
}

enum TipoEstadoAlertaSonora {
    ESTADO_ALERTA_SILENCIO,
    ESTADO_ALERTA_SONANDO      
}

TipoEstadoAlarma estadoAlarma = ESTADO_ALARMA_DESCONECTADA;
TipoEstadoAlertaSonora estadoAlertaSonora = ESTADO_ALERTA_SONANDO;

La parte del código que teníamos antes:

    if (estadoAlarma == ESTADO_ALARMA_DESCONECTADA || estadoAlarma == ESTADO_ALARMA_CONECTADA) {
        estadoAlertaSonora = ESTADO_ALERTA_SILENCIO;
    }
    if (estadoAlarma == ESTADO_ALARMA_SONANDO) {
        estadoAlertaSonora = ESTADO_ALERTA_SONANDO;
    }

No ha de cambiar. Funciona exactamente igual. Y ahora viene la pregunta ¿tanta parafernalia para nada, para que todo quede igual? Pues sí y no. Sí, todo queda igual, pero si por un despiste nos hemos equivocado y escrito mal el código:

    if (estadoAlarma == ESTADO_ALARMA_DESCONECTADA || estadoAlarma == ESTADO_ALARMA_CONECTADA) {
        estadoAlertaSonora = ESTADO_ALERTA_SILENCIO;
    }
    if (estadoAlarma == ESTADO_ALERTA_SONANDO) {    //   <--- Esta línea está mal
        estadoAlertaSonora = ESTADO_ALARMA_SONANDO; //   <--- Esta otra línea también está mal
    }

He intercambiado “accidentalmente” en el trozo de código anterior las constantes ESTADO_ALERTA_SONANDO y ESTADO_ALARMA_SONANDO (es el problema que de poner nombres tan parecido a dos cosas diferentes). Si hubiera usado los números como al principio, “estaría claro” que 2 y 1 no son lo mismo y que los he intercambiado :). Pero tanto con los números como si hubiera definido las constantes con el #define y el const, el compilador no me habría dicho absolutamente nada y habría compilado sin rechistar.

Ahí está la diferencia (no siempre), ya que dependiendo del compilador y de cómo esté configurado, podría darse el caso de no decir nada, de avisarnos o de dar un error. En la comparación (estadoAlarma == ESTADO_ALERTA_SONANDO) he podido comprobar que mi IDE de Arduino versión 1.6.8 no dice nada y compila sin más (por suerte para mi yo no uso el IDE sino la herramienta makeino de linux y ésta compila igualmente, pero me da un aviso de que estoy comparando entre dos enumerados diferentes. Y yo suelo vigilar que no me de ningún aviso al compila).

Pero en la asignación estadoAlertaSonora = ESTADO_ALARMA_SONANDO; sí que da un error con el IDE y con el makeino. Porque le estoy asignando a una variable de un tipo enumerado un valor de un tipo enumerado diferente.

Por desgracia dependemos un poco de cómo esté configurado el entorno para poder sacarle partido a lo básico del enum, pero aún así nos puede ayudar en más de una vez. Así que evalúa ahora si vale la pena el esfuerzo de hacer las cosas más o menos bien, o simplemente hacerlas.

Sé que lo que he dicho es un galimatías, pero espero que aún así te haya aclarado algo.

1 Like