Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Regla 0x5003h: Utilizá guardas de inclusión en todos los archivos de cabecera

Compilacion, preprocesador y seguridad (0x50XX)

Universidad Nacional de Río Negro

0x5003h: Utilizá guardas de inclusión en todos los archivos de cabecera

Enunciado normativo

DEBE envolverse el contenido de todo archivo de cabecera (.h) entre una directiva #ifndef NOMBRE_H, su #define NOMBRE_H y el #endif final. El macro de guarda DEBE ser único y derivado del nombre del archivo.

¿Por qué existe esta regla?

El problema

El preprocesador no recuerda qué archivos ya incluyó: cada #include copia el texto completo del encabezado. Si un mismo .h se alcanza por dos caminos distintos (por ejemplo, main.c incluye lista.h y pila.h, y ambos incluyen nodo.h), su contenido se duplica y produce redefiniciones de struct, typedef y prototipos. La guarda es idempotente: la primera inclusión define el macro y procesa el cuerpo; las siguientes no hacen nada.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
Compilaciónerror: redefinition of 'struct nodo' o de un typedef.
Bug silenciosoMacros redefinidas con valores distintos según el orden de inclusión.
MantenibilidadEl orden de los #include se vuelve significativo y frágil.
EscalabilidadUn .h que hoy funciona en un solo .c falla al reutilizarse.

Fundamento en el estándar y en la cátedra

ISO/IEC 9899:2011 §6.10.1 define #ifndef/#define/#endif como directivas de compilación condicional, y §6.10.3.5/§7 tratan la redefinición de macros. C no exige guardas: la cátedra las vuelve obligatorias porque todo se compila con varios módulos y -Werror. gaff fix inserta la guarda estándar.

Alcance y excepciones

Aplica a todo .h, incluso a los que hoy se incluyen una sola vez, porque la reutilización es la norma. No resuelve inclusiones cíclicas (0x5012h: Detección de inclusiones cíclicas entre archivos de cabecera): si a.h incluye b.h y b.h incluye a.h, la guarda deja a uno de los dos a medio procesar. Tampoco arregla un diseño circular.

Ejemplos exhaustivos

❌ Contraejemplo 1 — Cabecera sin guarda

struct nodo {
    int dato;
    struct nodo *sig;
};

int lista_agregar(struct nodo **cabecera, int valor);

Por qué falla: al incluirse dos veces, struct nodo y el prototipo se redefinen. El diagnóstico aparece lejos de la causa, porque el #include duplicado suele estar escondido tras otro encabezado.

❌ Contraejemplo 2 — Guarda con nombre que choca

#ifndef LISTA_H
#define LISTA_H

#include <stddef.h>

int pila_apilar(int valor);

#endif

Por qué falla: es en realidad pila.h pero reutilizó el macro de lista.h; si lista.h ya definió LISTA_H, esta cabecera se saltea por completo y pila_apilar desaparece. Es la colisión descrita en 0x500Fh: Colisión de nombres de macroguardas entre archivos de cabecera distintos.

✅ Ejemplo conforme 1 — Guarda canónica

#ifndef LISTA_H
#define LISTA_H

#include <stddef.h>

struct nodo {
    int dato;
    struct nodo *sig;
};

int lista_agregar(struct nodo **cabecera, int valor);

#endif /* LISTA_H */

El nombre LISTA_H deriva del archivo y el #endif lleva un comentario que facilita ubicar el cierre cuando la cabecera crece.

✅ Ejemplo conforme 2 — Guarda que resiste doble inclusión indirecta

#ifndef PROYECTO_NODO_H
#define PROYECTO_NODO_H

struct nodo {
    int dato;
    struct nodo *sig;
};

#endif /* PROYECTO_NODO_H */

Con un prefijo de proyecto se reduce el riesgo de colisión entre cabeceras homónimas de módulos distintos. Convive con la norma de no usar prefijos reservados __ o _X (0x010Ah: Prohibición de identificadores con prefijos reservados para el compilador (__ o _[A-Z])).

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
gaffgaff check archivo.hReporta 0x5003h si falta la guarda; gaff fix la agrega.
gccgcc -E archivo.cSe observa el cuerpo duplicado si no hay guarda.

Checklist de autocontrol

Reglas relacionadas