Me preguntaba por qué estaba funcionando declarar una variable global en un archivo de encabezado que se incluye en múltiples fuentes en C
#ifndef INC_MAIN_H_ #define INC_MAIN_H_ int my_var; #endifPero asignarle un valor predeterminado no funciona:
#ifndef INC_MAIN_H_ #define INC_MAIN_H_ int my_var = 0; #endifMuestra múltiples errores de compilación en cada archivo donde incluyo este main.h
definición múltiple de `my_var'; app/src/testfile.o:app/inc/main.h:4: definido por primera vez aquí
Sé que declarar variables globales de esta manera no es la mejor práctica, pero no puedo entender por qué agregar una asignación podría causar errores de compilación y no puedo encontrar respuestas claras al respecto.
Con las herramientas de compilación y los modificadores que está utilizando, int my_var; actúa principalmente como una declaración que no es una definición. Se permiten múltiples declaraciones de un identificador de objeto.
int my_var = 0; es una definición. Debe haber una sola definición.
Debido a la historia del uso y desarrollo de C, int my_var; es técnicamente una definición tentativa . Si no hay una definición regular de my_var en la unidad de traducción (el archivo fuente que se está compilando, incluidos todos los archivos que incluye), actúa como una definición regular.
Sin embargo, cuando tiene esto en un archivo de encabezado que se incluye en varios archivos de origen, tiene varias definiciones. Cuando hay múltiples definiciones del mismo identificador de objeto con vinculación externa, el estándar C no define el comportamiento.
Cuando hay varias definiciones regulares, sus herramientas de compilación informan un error. Sin embargo, tratan las definiciones que provienen de definiciones tentativas de manera diferente: las permiten y las fusionan en una sola definición. Una vez más, esto se debe a la historia de cómo se desarrolló y utilizó C. Además, este comportamiento cambió en GCC recientemente. Antes de la versión 10 de GCC, las definiciones tentativas se fusionaban de forma predeterminada, como se describe anteriormente. Con GCC 10 y versiones posteriores, las definiciones provisionales no se fusionan y las definiciones múltiples generarán un error. El antiguo comportamiento se puede solicitar con el -fcommon .
Para evitar definiciones tentativas, debe declarar el identificador en el encabezado como extern int my_var; , que es solo una declaración y no una definición tentativa, y debe tener exactamente un archivo fuente que contenga int my_var = 0; , que es una definición regular y no una definición tentativa.