Guardas de inclusión
Parte de la sección Object Oriented Programming del Journey de C de Coddy — lección 2 de 61.
Cuando un archivo de cabecera se incluye varias veces en un proyecto, el compilador ve las mismas declaraciones repetidamente, lo que provoca errores. Esto sucede comúnmente cuando varios archivos incluyen la misma cabecera, o cuando las cabeceras se incluyen entre sí. Los protectores de inclusión (include guards) resuelven este problema.
Una guarda de inclusión utiliza tres directivas de preprocesador para asegurar que el contenido de un encabezado se procese solo una vez:
// math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
int add(int a, int b);
#endif
Así es como funciona: #ifndef MATH_UTILS_H comprueba si el símbolo MATH_UTILS_H no ha sido definido aún. Si no lo ha sido, el preprocesador continúa e inmediatamente lo define con #define MATH_UTILS_H. Todo lo que se encuentra entre este punto y #endif se incluye en la compilación.
La segunda vez que se incluye este encabezado, MATH_UTILS_H ya está definido, por lo que se omite todo el bloque. El nombre de la guarda suele ser el nombre del archivo en mayúsculas, con guiones bajos sustituyendo a los puntos y caracteres especiales.
Cada archivo de cabecera que crees debe tener guardas de inclusión. Esta es una práctica estándar que evita errores de compilación y hace que tu código sea seguro de incluir desde cualquier parte de tu proyecto.
Desafío
FácilVamos a proteger un archivo de cabecera contra la inclusión doble añadiendo guardas de inclusión (include guards). Te basarás en la utilidad de saludo de la lección anterior, pero esta vez asegúrate de que la cabecera sea segura para ser incluida varias veces.
Crearás dos archivos:
greet.h: Tu archivo de cabecera que contiene la declaración de la función paragreet. Esta vez, envuelve todo el contenido con guardas de inclusión utilizando el símboloGREET_H.main.c: Tu archivo principal que incluye la cabecera, implementa la funcióngreety la llama desdemain().
La función greet debe aceptar un parámetro const char* para el nombre e imprimir:
Hello, Alice!Tu archivo de cabecera debe seguir esta estructura:
#ifndef GREET_H
#define GREET_H
// function declaration here
#endifRecibirás una entrada: un nombre (string).
Imprime el mensaje de saludo exactamente como se muestra en el formato anterior, reemplazando Alice con el nombre proporcionado.
Hoja de referencia
Las guardas de inclusión evitan que los archivos de cabecera se procesen varias veces durante la compilación, lo que causaría errores.
Una guarda de inclusión utiliza tres directivas de preprocesador:
#ifndef HEADER_NAME_H
#define HEADER_NAME_H
// contenido de la cabecera aquí
#endif
#ifndef comprueba si un símbolo no ha sido definido. Si no está definido, #define lo define y se procesa el contenido. En inclusiones posteriores, el símbolo ya está definido, por lo que se omite todo el bloque.
El nombre de la guarda suele ser el nombre del archivo en mayúsculas, sustituyendo los puntos y caracteres especiales por guiones bajos.
Todo archivo de cabecera debería tener guardas de inclusión como práctica estándar.
Pruébalo tú mismo
#include <stdio.h>
#include "greet.h"
// TODO: Implementa la función greet que imprima "Hello, <name>!"
int main() {
char name[100];
scanf("%s", name);
// TODO: Llama a la función greet con el name
return 0;
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
1Fundamentos de programación modular
Archivos de cabeceraGuardas de inclusiónArchivos fuenteFunciones estáticasRepaso: Calculadora modular4Encapsulamiento
Concepto de punteros opacosDefinición de structs opacosGetters y SettersValidación en settersResumen: Caja secreta7Punteros a funciones
Declaración de punteros a funcionesLlamada a punteros a funcionesTypedef para punteros a funcionesPasar funciones como argumentosRepaso: Dispatch de calculadora10Contenedores genéricos
Repaso de punteros voidWrapper genéricoSwap genéricoComparación genéricaRepaso: Array genérico2Objetos y métodos
Structs como objetosEl puntero 'Self'Const CorrectnessPuntero vs. ValorMétodos auxiliaresResumen: Point Manager5Proyecto: Cuenta bancaria simple
Configuración del proyectoImplementación de la cuenta3Ciclo de vida de los objetos
Patrón ConstructorPatrón DestructorInicialización en StackCopia profundaResumen: String Wrapper6Herencia mediante composición
Incrustación de StructsLa regla del primer miembroAcceso a miembros padreUpcastingResumen: Jerarquía de formas9Proyecto: Dibujador de figuras
Descripción general del proyectoImplementación del círculo