Regla 0x5011h: Prohibición de declaraciones extern en archivos de implementación (.c)
Compilacion, preprocesador y seguridad (0x50XX)
0x5011h: Prohibición de declaraciones extern en archivos de implementación (.c)¶
Enunciado normativo¶
NO DEBEN escribirse declaraciones
externen un archivo.c. Las entidades compartidas se declaran una sola vez en la cabecera.hy el.cla incluye.
¿Por qué existe esta regla?¶
El problema¶
Cuando main.c escribe extern int g_config; o extern void procesar(int);
directamente, crea una declaración paralela a la real. Si se equivoca en el
tipo, en la cantidad de parámetros o en el nombre, el compilador no lo detecta:
cada unidad se compila por separado y el error aparece en el enlace o, peor, en
ejecución con comportamiento indefinido. La cabecera existe para que esa
declaración sea única y verificada; el extern suelto también oculta de qué
módulo proviene el símbolo.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Comportamiento indefinido | Prototipo local incompatible con la definición real: argumentos mal pasados. |
| Compilación | El error aparece como símbolo no resuelto en el enlace, sin pistas. |
| Mantenibilidad | La dependencia entre módulos queda invisible en los #include. |
Fundamento en el estándar y en la cátedra¶
ISO/IEC 9899:2011 §6.2.2 distingue enlace externo e interno y §6.9 las
definiciones externas. Una declaración sin inicializador en una cabecera es el
mecanismo previsto para compartir tipos y firmas de forma verificada. La cátedra
exige que toda interfaz pase por el .h para tener un único punto de verdad.
Alcance y excepciones¶
Aplica a variables y funciones con enlace externo declaradas en .c. La propia
cabecera sí contiene declaraciones extern (es su propósito). Las globales
están prohibidas por 0x2004h: No se permite el uso de variables globales, de modo que los casos habituales son
funciones compartidas. Una declaración static no cae bajo esta regla.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — Variable compartida declarada en main.c¶
extern int g_config;
int main(void)
{
return g_config;
}Por qué falla: la declaración está copiada a mano. Si el módulo que define
g_config cambia su tipo a long, este archivo sigue creyendo que es int y
lee mal la variable. La declaración debería estar en un encabezado.
❌ Contraejemplo 2 — Prototipo local con firma equivocada¶
extern double calcular(int x, int y);
int main(void)
{
return (int)calcular(3, 4);
}Por qué falla: si la definición real es int calcular(int x, int y), el
compilador de main.c no puede saberlo. La discrepancia produce comportamiento
indefinido sin ninguna advertencia.
✅ Ejemplo conforme 1 — Todo declarado en la cabecera¶
/* config.h */
#ifndef CONFIG_H
#define CONFIG_H
extern int g_config;
int config_leer(void);
#endif/* main.c */
#include "config.h"
int main(void)
{
return g_config;
}La declaración vive en un solo lugar y todo archivo que la use incluye la cabecera. Cualquier cambio de firma se propaga y el compilador lo verifica.
✅ Ejemplo conforme 2 — Función privada con static¶
#include "calculo.h"
static int normalizar(int x)
{
return x % 100;
}
int calculo_valor(int x)
{
return normalizar(x) + 1;
}normalizar tiene enlace interno: no se comparte con otras unidades y por lo
tanto no necesita extern ni declaración en la cabecera. Sólo lo público
atraviesa el .h.
⚠️ Casos límite¶
externen la cabecera: correcto y esperado; la regla sólo prohíbe el.c.extern "C": es una construcción de C++, no de C; no aplica.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Reporta 0x5011h ante una declaración extern en un .c. |
gcc / ld | gcc main.c modulo.c -o app | undefined reference si la firma copiada no coincide con la real. |
Checklist de autocontrol¶
¿Algún
.cdeclaraexternpor su cuenta?¿Todas las funciones compartidas están prototipadas en su
.h?¿Las funciones internas usan
staticy noextern?
Reglas relacionadas¶
0x0205h: En archivos .c la inclusión de la cabecera propia debe figurar en primer lugar — la interfaz del módulo se expone mediante su cabecera.
0x500Ch: Prohibición de inclusión directa de archivos de código fuente C (.c) — la compilación separada es la que permite verificar firmas.