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 0x500Ch: Prohibición de inclusión directa de archivos de código fuente C (.c)

Compilacion, preprocesador y seguridad (0x50XX)

Universidad Nacional de Río Negro

0x500Ch: Prohibición de inclusión directa de archivos de código fuente C (.c)

Enunciado normativo

NO DEBE incluirse un archivo .c con #include. Para compartir código se incluye la cabecera .h y se compilan todos los .c en el enlace.

¿Por qué existe esta regla?

El problema

#include "modulo.c" copia el cuerpo completo de un módulo dentro del archivo que lo incluye, en vez de tratarlo como una unidad de traducción separada. Si modulo.c ya se compiló por su cuenta, sus funciones quedan definidas dos veces y el enlazador aborta con «multiple definition». Si no se compiló, el módulo deja de ser independiente y pierde el propósito de ocultar su estado interno: las funciones static y las variables de archivo quedan visibles desde el cliente.

La compilación separada es el mecanismo con el que C estructura programas grandes: cada .c se compila a un .o y el enlazador los une. Incluir .c ataca justamente ese mecanismo.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
Enlacemultiple definition of 'funcion'; si el .c tiene main, choca con el del cliente.
EncapsulamientoEl cliente ve y puede pisar los símbolos static del módulo.
CompilaciónCada cambio del .c incluido recompila todo el proyecto.
MantenibilidadLa frontera entre módulos se borra y crecen las dependencias ocultas.

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

ISO/IEC 9899:2011 §5.1.1.1 describe el modelo de compilación separada y §6.9 las definiciones externas: cada entidad externa se define una sola vez en todo el programa. Incluir un .c rompe esa unicidad. La cátedra exige #include sólo para .h porque el proyecto se compila con gcc main.c modulo.c.

Alcance y excepciones

Aplica a cualquier #include cuyo argumento termine en .c. Excepción legítima: los archivos de X-macros con extensión propia (.def, .inc) que se incluyen a propósito y no se compilan solos. También puede aparecer #include "impl.c" en pruebas muy acotadas para acceder a funciones static, pero en la materia se considera una violación.

Ejemplos exhaustivos

❌ Contraejemplo 1 — Incluir el .c en lugar del .h

#include "modulo.h"
#include "modulo.c"

int main(void)
{
    return modulo_calcular(2);
}

Por qué falla: se compila main.c y además modulo.c por separado; modulo queda definido dos veces y el enlazador falla. El #include "modulo.c" es también la causa de que el módulo deje de ser reutilizable.

❌ Contraejemplo 2 — Incluir un .c que trae main

#include "otro_programa.c"

int main(void)
{
    return 0;
}

Por qué falla: otro_programa.c contiene su propio main, así que la unidad de traducción termina con dos definiciones de main y el enlazador aborta. El código de otro ejecutable nunca se reutiliza por inclusión.

✅ Ejemplo conforme 1 — Cabecera y compilación separada

#include "modulo.h"

int main(void)
{
    return modulo_calcular(2);
}
gcc -std=c11 -Wall -Wextra -Werror -pedantic main.c modulo.c -o app

main.c sólo ve la interfaz declarada en modulo.h; modulo.c se compila aparte y el enlazador une ambos objetos. Cada módulo conserva su estado interno.

✅ Ejemplo conforme 2 — X-macro con extensión propia

static const char *const nombres[] = {
#include "estados.inc"
};

estados.inc no es una unidad de traducción: se incluye para generar código y no se compila por sí solo. Es la excepción prevista; nunca se usa la extensión .c para este patrón.

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
gaffgaff check archivo.cReporta 0x500Ch ante #include "...c".
gcc / ldgcc main.c modulo.c -o appmultiple definition of 'modulo_calcular'.
Revisión manual#include con extensión .c en el bloque de includes.

Checklist de autocontrol

Reglas relacionadas