¿Debería estar la definición de variable en los archivos de encabezado?

3 minutos de lectura

avatar de usuario
métodos

Mi conocimiento muy básico de C y el proceso de compilación se ha oxidado últimamente. Estaba tratando de encontrar la respuesta a la siguiente pregunta, pero no pude conectar los conceptos básicos de compilación, enlace y fase de preprocesamiento. Una búsqueda rápida en Google tampoco ayudó mucho. Entonces, decidí venir a la última fuente de conocimiento 🙂

Sé: Las variables no deben definirse en los archivos .h. Está bien declararlos allí.

Por qué: Porque un archivo de encabezado puede incluirse desde varios lugares, redefiniendo así la variable más de una vez (Linker da el error).

Posible solución alternativa: Use protectores de encabezado en archivos de encabezado y defina variables en eso.

¿Es realmente una solución? No. Porque los header-guards son para la fase de preprocesamiento. Eso es para decirle al compilador que esta parte ya se ha incluido y que no la vuelva a incluir. Pero nuestro error de definición múltiple viene en la parte del enlazador, mucho después de la compilación.

Todo esto me tiene confundido acerca de cómo funcionan el preprocesamiento y la vinculación. Pensé que el preprocesamiento simplemente no incluiría el código, si se ha definido el símbolo de protección del encabezado. En ese caso, ¿no debería resolverse también el problema de definición múltiple de una variable?

¿Qué sucede si estas directivas de preprocesamiento evitan que el proceso de compilación redefina los símbolos bajo las protecciones de encabezado, pero el enlazador aún obtiene múltiples definiciones del símbolo?

Una cosa que he usado en el pasado (cuando las variables globales estaban de moda):

archivo var.h:

...
#ifdef DEFINE_GLOBALS
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN int global1;
EXTERN int global2;
...

luego en una Archivo .c (generalmente el que contiene main()):

#define DEFINE_GLOBALS
#include "var.h"

El resto de los archivos fuente solo incluyen “var.h” normalmente.

Tenga en cuenta que DEFINE_GLOBALS no es un protector de encabezado, sino que permite declarar/definir las variables dependiendo de si está definida. Esta técnica permite una copia de las declaraciones/definiciones.

La protección de encabezado lo protege de múltiples inclusiones en un solo archivo de origen, no de múltiples archivos de origen. Supongo que tu problema radica en no entender este concepto.

No es que los protectores del preprocesador se guarden durante el tiempo de compilación debido a este problema. En realidad, durante el tiempo de compilación, un solo archivo fuente se compila en un obj, las definiciones de símbolos no se resuelven. Pero, en caso de vincular cuando el vinculador intenta resolver las definiciones de los símbolos, se confunde al ver más de una definición, lo que hace que marque el error.

Tienes dos archivos .c. se compilan por separado. Cada uno incluye su archivo de cabecera. Una vez. Cada uno tiene una definición. Ellos entran en conflicto en el momento del enlace.

La solución convencional es:

#ifdef DEFINE_SOMETHING
int something = 0;
#endif

Luego #define DEFINE_SOMETHING en sólo uno archivo .c.

  • Una mejor solución es una declaración en el encabezado y una definición en un solo archivo .c.

    – William Pursell

    7 de febrero de 2010 a las 17:03

Los protectores de encabezado evitan que un archivo de encabezado se incluya varias veces en la misma unidad de traducción (es decir, en el mismo archivo fuente .c). No tienen efecto si incluye el archivo en dos o más unidades de traducción.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad