C

C

Tutorial C: Enumeraciones

Aprende en C cómo usar enumeraciones para definir constantes relacionadas con valores automáticos y específicos, mejorando legibilidad y mantenimiento.

Aprende C y certifícate

enum para constantes relacionadas

Las enumeraciones (o enum) en C son una herramienta muy útil para definir un conjunto de constantes relacionadas entre sí, dándoles nombres significativos en lugar de usar valores numéricos directamente en el código. Esto hace que nuestros programas sean más legibles y mantenibles.

¿Qué es una enumeración?

Una enumeración es un tipo de dato definido por el usuario que consiste en un conjunto de valores constantes con nombre. En lugar de usar números "mágicos" dispersos por el código, podemos agruparlos bajo un nombre descriptivo.

La sintaxis básica para declarar una enumeración es:

enum nombre_enumeracion {
    VALOR1,
    VALOR2,
    VALOR3,
    // ...
};

Ejemplo práctico: Días de la semana

Veamos un ejemplo sencillo donde las enumeraciones resultan muy útiles:

#include <stdio.h>

enum DiaSemana {
    LUNES,
    MARTES,
    MIERCOLES,
    JUEVES,
    VIERNES,
    SABADO,
    DOMINGO
};

int main() {
    enum DiaSemana hoy = MIERCOLES;
    
    printf("Hoy es el día número: %d\n", hoy);
    
    if (hoy == MIERCOLES) {
        printf("Mitad de semana laboral\n");
    }
    
    return 0;
}

En este ejemplo, hemos creado una enumeración llamada DiaSemana que contiene los siete días de la semana. Internamente, C asigna valores enteros a cada constante, comenzando desde 0.

Uso con switch

Las enumeraciones son especialmente útiles cuando se combinan con la estructura switch, haciendo que el código sea mucho más claro y expresivo:

#include <stdio.h>

enum EstadoTarea {
    PENDIENTE,
    EN_PROGRESO,
    COMPLETADA,
    CANCELADA
};

void mostrar_estado(enum EstadoTarea estado) {
    switch (estado) {
        case PENDIENTE:
            printf("La tarea está pendiente de iniciar\n");
            break;
        case EN_PROGRESO:
            printf("La tarea se está ejecutando actualmente\n");
            break;
        case COMPLETADA:
            printf("La tarea ha sido completada con éxito\n");
            break;
        case CANCELADA:
            printf("La tarea fue cancelada\n");
            break;
        default:
            printf("Estado desconocido\n");
    }
}

int main() {
    enum EstadoTarea miTarea = EN_PROGRESO;
    mostrar_estado(miTarea);
    
    return 0;
}

Enumeraciones como enteros

Es importante entender que las enumeraciones en C son realmente valores enteros. Podemos comprobar esto fácilmente:

#include <stdio.h>

enum Colores {
    ROJO,    // 0
    VERDE,   // 1
    AZUL,    // 2
    AMARILLO // 3
};

int main() {
    enum Colores color = VERDE;
    
    printf("ROJO = %d\n", ROJO);
    printf("VERDE = %d\n", VERDE);
    printf("AZUL = %d\n", AZUL);
    printf("AMARILLO = %d\n", AMARILLO);
    
    // Podemos realizar operaciones aritméticas
    int siguiente_color = color + 1;
    printf("El siguiente color después de VERDE es: %d (AZUL)\n", siguiente_color);
    
    return 0;
}

Ventajas de usar enumeraciones

  • Legibilidad mejorada: if (dia == SABADO) es mucho más claro que if (dia == 5).
  • Mantenimiento simplificado: Si necesitas cambiar el valor de una constante, solo lo haces en un lugar.
  • Prevención de errores: Ayuda a evitar asignar valores incorrectos a variables.
  • Documentación implícita: El nombre de la enumeración y sus valores actúan como documentación del código.

Ejemplo de uso en un menú de opciones

Las enumeraciones son perfectas para representar opciones en menús:

#include <stdio.h>

enum OpcionMenu {
    GUARDAR = 1,
    CARGAR,
    CONFIGURAR,
    SALIR
};

int main() {
    int seleccion;
    enum OpcionMenu opcion;
    
    printf("MENÚ PRINCIPAL\n");
    printf("1. Guardar archivo\n");
    printf("2. Cargar archivo\n");
    printf("3. Configuración\n");
    printf("4. Salir\n");
    printf("Seleccione una opción: ");
    scanf("%d", &seleccion);
    
    opcion = (enum OpcionMenu)seleccion;
    
    switch (opcion) {
        case GUARDAR:
            printf("Guardando archivo...\n");
            break;
        case CARGAR:
            printf("Cargando archivo...\n");
            break;
        case CONFIGURAR:
            printf("Abriendo configuración...\n");
            break;
        case SALIR:
            printf("Saliendo del programa...\n");
            break;
        default:
            printf("Opción no válida\n");
    }
    
    return 0;
}

Declaración de variables de tipo enum

Podemos declarar variables de tipo enumeración de varias formas:

// Forma 1: Declarar la enumeración y luego la variable
enum Direccion {
    NORTE,
    SUR,
    ESTE,
    OESTE
};
enum Direccion rumbo = NORTE;

// Forma 2: Declarar la enumeración y la variable al mismo tiempo
enum Estacion {
    PRIMAVERA,
    VERANO,
    OTONO,
    INVIERNO
} estacion_actual = VERANO;

Las enumeraciones son una herramienta fundamental para escribir código más claro y mantenible en C, especialmente cuando trabajamos con conjuntos de constantes relacionadas que representan estados, opciones o categorías.

Valores automáticos desde 0

Cuando creamos una enumeración en C, uno de sus aspectos más prácticos es la asignación automática de valores a cada constante. Por defecto, C asigna valores enteros comenzando desde 0 y aumentando de uno en uno para cada elemento de la enumeración.

Comportamiento predeterminado

En una enumeración simple, el primer elemento recibe el valor 0, el segundo el valor 1, y así sucesivamente:

enum Semaforo {
    ROJO,     // 0
    AMARILLO, // 1
    VERDE     // 2
};

Podemos comprobar estos valores fácilmente:

#include <stdio.h>

enum Semaforo {
    ROJO,
    AMARILLO,
    VERDE
};

int main() {
    printf("ROJO = %d\n", ROJO);
    printf("AMARILLO = %d\n", AMARILLO);
    printf("VERDE = %d\n", VERDE);
    
    return 0;
}

Este programa mostrará:

ROJO = 0
AMARILLO = 1
VERDE = 2

Uso práctico de los valores automáticos

Esta asignación automática resulta muy conveniente para muchas situaciones comunes:

  • Indexación de arrays: Los valores de enumeración pueden usarse directamente como índices.
  • Iteración secuencial: Facilita recorrer todos los valores de una enumeración.
  • Representación de estados ordenados: Ideal para estados que siguen una progresión natural.

Veamos un ejemplo donde aprovechamos los valores automáticos para indexar un array:

#include <stdio.h>

enum Planeta {
    MERCURIO,  // 0
    VENUS,     // 1
    TIERRA,    // 2
    MARTE,     // 3
    JUPITER,   // 4
    SATURNO,   // 5
    URANO,     // 6
    NEPTUNO    // 7
};

int main() {
    // Array con los diámetros de los planetas (en km)
    int diametros[] = {4880, 12104, 12756, 6794, 142984, 120536, 51118, 49528};
    
    enum Planeta miPlaneta = TIERRA;
    
    printf("El diámetro de la Tierra es: %d km\n", diametros[miPlaneta]);
    
    // Iteramos por todos los planetas
    for (enum Planeta p = MERCURIO; p <= NEPTUNO; p++) {
        printf("Planeta %d tiene un diámetro de %d km\n", p, diametros[p]);
    }
    
    return 0;
}

Conteo de elementos en una enumeración

Una técnica útil es añadir un elemento adicional al final de la enumeración para obtener automáticamente el número total de elementos:

#include <stdio.h>

enum DiaSemana {
    LUNES,
    MARTES,
    MIERCOLES,
    JUEVES,
    VIERNES,
    SABADO,
    DOMINGO,
    NUM_DIAS  // Este valor será 7
};

int main() {
    int asistencia[NUM_DIAS] = {0}; // Inicializa un array con el tamaño exacto
    
    printf("La semana tiene %d días\n", NUM_DIAS);
    printf("Tamaño del array de asistencia: %lu bytes\n", 
           sizeof(asistencia));
    
    return 0;
}

Verificación de rangos

Los valores automáticos también facilitan la verificación de rangos para asegurar que un valor está dentro de los límites válidos:

#include <stdio.h>

enum Mes {
    ENERO,
    FEBRERO,
    MARZO,
    ABRIL,
    MAYO,
    JUNIO,
    JULIO,
    AGOSTO,
    SEPTIEMBRE,
    OCTUBRE,
    NOVIEMBRE,
    DICIEMBRE,
    NUM_MESES
};

int es_mes_valido(int mes) {
    return (mes >= ENERO && mes < NUM_MESES);
}

int main() {
    int mes = 5;  // JUNIO (recuerda que empezamos desde 0)
    
    if (es_mes_valido(mes)) {
        printf("El mes %d es válido\n", mes);
    } else {
        printf("El mes %d no es válido\n", mes);
    }
    
    // Probamos con un valor fuera de rango
    mes = 15;
    if (es_mes_valido(mes)) {
        printf("El mes %d es válido\n", mes);
    } else {
        printf("El mes %d no es válido\n", mes);
    }
    
    return 0;
}

Conversión implícita a enteros

Es importante recordar que las enumeraciones en C son tipos enteros y pueden usarse en cualquier contexto donde se espera un entero:

#include <stdio.h>

enum Nivel {
    PRINCIPIANTE,  // 0
    INTERMEDIO,    // 1
    AVANZADO       // 2
};

int main() {
    enum Nivel nivel_usuario = INTERMEDIO;
    
    // Operaciones aritméticas
    int siguiente_nivel = nivel_usuario + 1;
    
    // Comparaciones
    if (nivel_usuario < AVANZADO) {
        printf("El usuario aún puede subir de nivel\n");
    }
    
    // Incremento
    nivel_usuario++;
    printf("Nuevo nivel: %d\n", nivel_usuario);
    
    return 0;
}

Consideraciones importantes

  • Los valores automáticos son predecibles y secuenciales, lo que facilita el razonamiento sobre el código.
  • Si no necesitas valores específicos, dejar que C asigne automáticamente los valores suele ser la opción más limpia y mantenible.
  • Recuerda que aunque puedes realizar operaciones aritméticas con enumeraciones, debes tener cuidado de no producir valores fuera del rango definido.

Esta asignación automática de valores desde 0 es una característica fundamental de las enumeraciones en C que las hace especialmente útiles para representar conjuntos ordenados de constantes relacionadas.

Asignar valores específicos

Aunque la asignación automática de valores en las enumeraciones es conveniente, C también nos permite asignar valores específicos a los elementos de una enumeración. Esta característica resulta extremadamente útil cuando necesitamos que nuestras constantes tengan valores concretos por razones de compatibilidad, legibilidad o lógica de negocio.

Sintaxis para asignar valores

Para asignar un valor específico a un elemento de una enumeración, simplemente usamos el operador de asignación (=) seguido del valor deseado:

enum NombreEnum {
    CONSTANTE1 = valor1,
    CONSTANTE2 = valor2,
    CONSTANTE3 = valor3
};

Ejemplo básico

Veamos un ejemplo sencillo donde asignamos valores específicos a los meses del año:

#include <stdio.h>

enum Mes {
    ENERO = 1,    // Comenzamos desde 1 en lugar de 0
    FEBRERO = 2,
    MARZO = 3,
    ABRIL = 4,
    MAYO = 5,
    JUNIO = 6,
    JULIO = 7,
    AGOSTO = 8,
    SEPTIEMBRE = 9,
    OCTUBRE = 10,
    NOVIEMBRE = 11,
    DICIEMBRE = 12
};

int main() {
    enum Mes mes_actual = ABRIL;
    
    printf("El mes actual es: %d\n", mes_actual);
    
    return 0;
}

En este caso, hemos asignado valores del 1 al 12 para que coincidan con la numeración tradicional de los meses, en lugar de usar la numeración predeterminada que comenzaría desde 0.

Continuación de la secuencia

Un aspecto interesante es que después de asignar un valor específico, los elementos siguientes continuarán la secuencia a partir de ese valor:

#include <stdio.h>

enum Calificacion {
    SUSPENSO = 0,
    APROBADO = 5,  // Asignamos 5 explícitamente
    NOTABLE,       // Será 6 automáticamente
    SOBRESALIENTE  // Será 7 automáticamente
};

int main() {
    printf("SUSPENSO = %d\n", SUSPENSO);
    printf("APROBADO = %d\n", APROBADO);
    printf("NOTABLE = %d\n", NOTABLE);
    printf("SOBRESALIENTE = %d\n", SOBRESALIENTE);
    
    return 0;
}

Este programa mostrará:

SUSPENSO = 0
APROBADO = 5
NOTABLE = 6
SOBRESALIENTE = 7

Valores no secuenciales

Podemos asignar valores completamente no secuenciales si así lo requerimos:

#include <stdio.h>

enum CodigosError {
    EXITO = 0,
    ERROR_ARCHIVO = 100,
    ERROR_RED = 200,
    ERROR_MEMORIA = 500,
    ERROR_DESCONOCIDO = 999
};

int main() {
    enum CodigosError resultado = ERROR_RED;
    
    printf("Código de resultado: %d\n", resultado);
    
    if (resultado != EXITO) {
        printf("Se produjo un error durante la operación\n");
    }
    
    return 0;
}

Valores duplicados

C permite asignar el mismo valor a diferentes constantes de una enumeración:

#include <stdio.h>

enum Booleano {
    FALSO = 0,
    NO = 0,    // Mismo valor que FALSO
    VERDADERO = 1,
    SI = 1     // Mismo valor que VERDADERO
};

int main() {
    enum Booleano respuesta = SI;
    
    if (respuesta == VERDADERO) {
        printf("Las constantes tienen el mismo valor\n");
    }
    
    return 0;
}

Uso con máscaras de bits

Una aplicación muy común de los valores específicos en enumeraciones es la creación de máscaras de bits para operaciones de banderas:

#include <stdio.h>

enum Permisos {
    NINGUNO = 0,
    LECTURA = 1,        // 001 en binario
    ESCRITURA = 2,      // 010 en binario
    EJECUCION = 4       // 100 en binario
};

int main() {
    // Combinamos permisos usando el operador OR (|)
    int permisos_archivo = LECTURA | ESCRITURA;  // 3 (011 en binario)
    
    printf("Permisos del archivo: %d\n", permisos_archivo);
    
    // Verificamos si tiene permiso de lectura
    if (permisos_archivo & LECTURA) {
        printf("El archivo tiene permisos de lectura\n");
    }
    
    // Verificamos si tiene permiso de ejecución
    if (permisos_archivo & EJECUCION) {
        printf("El archivo tiene permisos de ejecución\n");
    } else {
        printf("El archivo NO tiene permisos de ejecución\n");
    }
    
    return 0;
}

En este ejemplo, usamos valores que son potencias de 2 (1, 2, 4) para que cada bit represente un permiso diferente. Esto nos permite combinar permisos usando operadores bit a bit.

Valores negativos y expresiones

También podemos asignar valores negativos o incluso expresiones a las constantes de una enumeración:

#include <stdio.h>

enum Temperatura {
    CONGELACION = 0,
    FRIO = -10,
    CALOR = 30,
    EBULLICION = 100,
    AMBIENTE = 20,
    CORPORAL = 37,
    FIEBRE = CORPORAL + 1  // Usando una expresión
};

int main() {
    printf("Temperatura de congelación: %d°C\n", CONGELACION);
    printf("Temperatura corporal: %d°C\n", CORPORAL);
    printf("Se considera fiebre a partir de: %d°C\n", FIEBRE);
    
    return 0;
}

Casos de uso prácticos

La asignación de valores específicos es especialmente útil en estos escenarios:

  • Compatibilidad con sistemas externos: Cuando necesitamos que nuestros códigos coincidan con valores definidos por APIs, protocolos o bases de datos.
  • Códigos de estado: Para definir códigos de error o estado que sigan convenciones establecidas.
  • Representación de valores reales: Cuando las constantes representan valores del mundo real (como temperaturas, fechas o medidas).
  • Optimización de memoria: En sistemas embebidos o con restricciones, podemos elegir valores que optimicen el almacenamiento.

Ejemplo: Días del mes

Un ejemplo práctico sería representar los días máximos de cada mes:

#include <stdio.h>

enum MesDias {
    ENERO_DIAS = 31,
    FEBRERO_DIAS = 28,  // Sin considerar años bisiestos
    MARZO_DIAS = 31,
    ABRIL_DIAS = 30,
    MAYO_DIAS = 31,
    JUNIO_DIAS = 30,
    JULIO_DIAS = 31,
    AGOSTO_DIAS = 31,
    SEPTIEMBRE_DIAS = 30,
    OCTUBRE_DIAS = 31,
    NOVIEMBRE_DIAS = 30,
    DICIEMBRE_DIAS = 31
};

int main() {
    enum MesDias dias_febrero = FEBRERO_DIAS;
    
    printf("Febrero normalmente tiene %d días\n", dias_febrero);
    
    // Verificamos si es año bisiesto (simplificado)
    int anio = 2024;
    if ((anio % 4 == 0 && anio % 100 != 0) || anio % 400 == 0) {
        printf("Pero en %d, que es bisiesto, tiene %d días\n", 
               anio, dias_febrero + 1);
    }
    
    return 0;
}

La asignación de valores específicos a las constantes de una enumeración nos brinda mayor flexibilidad y control, permitiéndonos crear código más expresivo y adaptado a las necesidades específicas de nuestras aplicaciones.

CONSTRUYE TU CARRERA EN IA Y PROGRAMACIÓN SOFTWARE

Accede a +1000 lecciones y cursos con certificado. Mejora tu portfolio con certificados de superación para tu CV.

30 % DE DESCUENTO

Plan mensual

19.00 /mes

13.30 € /mes

Precio normal mensual: 19 €
63 % DE DESCUENTO

Plan anual

10.00 /mes

7.00 € /mes

Ahorras 144 € al año
Precio normal anual: 120 €
Aprende C online

Todas las lecciones de C

Accede a todas las lecciones de C y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Accede GRATIS a C y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender qué es una enumeración y su sintaxis básica en C.
  • Aprender a utilizar enumeraciones para mejorar la legibilidad y mantenimiento del código.
  • Entender la asignación automática de valores enteros a los elementos de una enumeración.
  • Saber cómo asignar valores específicos a elementos de una enumeración y sus aplicaciones.
  • Aplicar enumeraciones en estructuras de control como switch y en casos prácticos como menús y máscaras de bits.