Regla 0x500Fh: Colisión de nombres de macroguardas entre archivos de cabecera distintos
Compilacion, preprocesador y seguridad (0x50XX)
0x500Fh: Colisión de nombres de macroguardas entre archivos de cabecera distintos¶
Enunciado normativo¶
NO DEBEN compartir macro de guarda dos cabeceras distintas. El nombre
NOMBRE_HDEBE derivar del archivo (idealmente con un prefijo de proyecto) y ser único en toda la unidad de traducción.
¿Por qué existe esta regla?¶
El problema¶
La guarda de inclusión usa un macro global a la unidad de traducción. Si
lista.h y pila.h usan ambas UTILS_H, al compilar main.c con lista.h
primero el preprocesador define UTILS_H y procesa su cuerpo. Cuando llega a
pila.h, encuentra el macro ya definido y saltea todo su contenido: ni los
prototipos ni los tipos existen. El error aparece en el archivo cliente, a
kilómetros de la causa real: no faltan guardas, los nombres están repetidos.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Compilación | El segundo encabezado se ignora; tipos y prototipos «desaparecen». |
| Funcionamiento | A veces compila según el orden de los #include, un bug intermitente. |
| Diagnóstico | El error aparece en el archivo cliente, no en la cabecera culpable. |
| Escalabilidad | Se agrava a medida que el proyecto suma módulos y cabeceras. |
Fundamento en el estándar y en la cátedra¶
ISO/IEC 9899:2011 §6.10.1 regula #ifndef/#define/#endif: la inclusión
condicional consulta un macro único en la unidad de traducción. La cátedra exige
nombres únicos, que son responsabilidad del programador y no del estándar.
Alcance y excepciones¶
Aplica a todas las cabeceras del proyecto; no hay excepción. Un patrón
robusto es prefijar con el proyecto o la carpeta (PROYECTO_LISTA_H) y, ante
módulos homónimos, incluir la distinción (SENSORES_LISTA_H). Evitá los
prefijos reservados __ y _ + mayúscula (0x010Ah: Prohibición de identificadores con prefijos reservados para el compilador (__ o _[A-Z])).
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — Misma guarda en dos cabeceras¶
/* lista.h */
#ifndef UTILS_H
#define UTILS_H
int lista_agregar(int valor);
#endif/* pila.h */
#ifndef UTILS_H
#define UTILS_H
int pila_apilar(int valor);
#endifPor qué falla: si main.c incluye lista.h antes que pila.h, esta última se
saltea completa y pila_apilar no existe. El error se reporta en main.c.
❌ Contraejemplo 2 — Prefijo reservado y genérico¶
#ifndef __UTILS_H__
#define __UTILS_H__
/* contenido */
#endifPor qué falla por dos motivos: el nombre se repite con cualquier otra cabecera
utils, y empieza con doble guion bajo, un prefijo reservado a la implementación
(0x010Ah: Prohibición de identificadores con prefijos reservados para el compilador (__ o _[A-Z])).
✅ Ejemplo conforme 1 — Guardas derivadas del proyecto¶
/* lista.h */
#ifndef PROYECTO_LISTA_H
#define PROYECTO_LISTA_H
int lista_agregar(int valor);
#endif/* pila.h */
#ifndef PROYECTO_PILA_H
#define PROYECTO_PILA_H
int pila_apilar(int valor);
#endifCada macro identifica sin ambigüedad a su archivo; incluir ambas cabeceras en cualquier orden produce el mismo resultado.
✅ Ejemplo conforme 2 — Cabeceras homónimas en carpetas distintas¶
/* sensores/lista.h */
#ifndef SENSORES_LISTA_H
#define SENSORES_LISTA_H
#endif
/* usuarios/lista.h */
#ifndef USUARIOS_LISTA_H
#define USUARIOS_LISTA_H
#endifCuando dos módulos tienen un archivo con el mismo nombre, la carpeta forma parte del macro de guarda y ambas interfaces conviven en una misma unidad.
⚠️ Casos límite¶
#pragma once: evita colisiones pero no es estándar; no reemplaza a la guarda si se busca portabilidad.Renombrar el archivo: hay que actualizar el macro; si no, queda desactualizado pero aún funcional.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check *.h | Reporta 0x500Fh al encontrar el mismo macro en dos cabeceras. |
gcc | gcc -H -E archivo.c | Una cabecera esperada no aparece procesada. |
Checklist de autocontrol¶
¿El macro de guarda de cada cabecera es distinto de todos los demás?
¿El nombre deriva del archivo y de su carpeta si hace falta?
¿Evité prefijos reservados
__y_+ mayúscula?¿Probé incluir juntas todas las cabeceras del módulo?
¿Actualicé el macro al renombrar o mover una cabecera?
Reglas relacionadas¶
0x5003h: Utilizá guardas de inclusión en todos los archivos de cabecera — toda cabecera debe tener guarda; esta regla pide que sea única.
0x010Ah: Prohibición de identificadores con prefijos reservados para el compilador (__ o _[A-Z]) — no usar prefijos reservados en el nombre de la guarda.
0x5012h: Detección de inclusiones cíclicas entre archivos de cabecera — las inclusiones cíclicas producen síntomas parecidos.