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 0x5011h: Prohibición de declaraciones extern en archivos de implementación (.c)

Compilacion, preprocesador y seguridad (0x50XX)

Universidad Nacional de Río Negro

0x5011h: Prohibición de declaraciones extern en archivos de implementación (.c)

Enunciado normativo

NO DEBEN escribirse declaraciones extern en un archivo .c. Las entidades compartidas se declaran una sola vez en la cabecera .h y el .c la 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 consecuenciaEfecto concreto
Comportamiento indefinidoPrototipo local incompatible con la definición real: argumentos mal pasados.
CompilaciónEl error aparece como símbolo no resuelto en el enlace, sin pistas.
MantenibilidadLa 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 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

Cómo detectarla

HerramientaComandoSeñal
gaffgaff check archivo.cReporta 0x5011h ante una declaración extern en un .c.
gcc / ldgcc main.c modulo.c -o appundefined reference si la firma copiada no coincide con la real.

Checklist de autocontrol

Reglas relacionadas