Regla 0x5003h: Utilizá guardas de inclusión en todos los archivos de cabecera
Compilacion, preprocesador y seguridad (0x50XX)
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_Hy el#endiffinal. 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 consecuencia | Efecto concreto |
|---|---|
| Compilación | error: redefinition of 'struct nodo' o de un typedef. |
| Bug silencioso | Macros redefinidas con valores distintos según el orden de inclusión. |
| Mantenibilidad | El orden de los #include se vuelve significativo y frágil. |
| Escalabilidad | Un .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);
#endifPor 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¶
Nombre reservado:
#ifndef __LISTA_Hempieza con doble guion bajo y está reservado a la implementación (0x010Ah: Prohibición de identificadores con prefijos reservados para el compilador (__ o _[A-Z])); usáLISTA_H.#pragma once: más corto, pero no es estándar ISO C; no reemplaza a la guarda si se busca portabilidad estricta.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.h | Reporta 0x5003h si falta la guarda; gaff fix la agrega. |
gcc | gcc -E archivo.c | Se observa el cuerpo duplicado si no hay guarda. |
Checklist de autocontrol¶
¿Cada
.hempieza con#ifndef NOMBRE_Hy#define NOMBRE_H?¿El macro deriva del nombre del archivo y es único en el proyecto?
¿El archivo cierra con
#endify un comentario con el macro?¿Evité nombres reservados (
__,_+ mayúscula)?¿Probé incluir la cabecera dos veces y compilar con
-Werror?
Reglas relacionadas¶
0x500Fh: Colisión de nombres de macroguardas entre archivos de cabecera distintos — macroguardas repetidas entre cabeceras distintas.
0x5012h: Detección de inclusiones cíclicas entre archivos de cabecera — inclusiones cíclicas, que la guarda no puede resolver.
0x010Ah: Prohibición de identificadores con prefijos reservados para el compilador (__ o _[A-Z]) — no usar prefijos reservados para el macro de guarda.