una - variables globales y locales en visual basic
ImplementaciĆ³n de variable global (4)
El enlazador permite tener datos externos duplicados como este (aunque me sorprende que los diferentes tipos no causen problemas). El que obtengas depende del orden de tus archivos objeto en tu línea de comando de enlace.
Cuando escribo el siguiente programa:
archivo 1:
#include <stdio.h>
int global;
void print_global1() {
printf("%p/n", &global);
}
archivo 2:
#include <stdio.h>
char global;
void print_global2() {
printf("%p/n", &global);
}
archivo 3:
void print_global1();
void print_global2();
int main()
{
print_global1();
print_global2();
return 0;
}
salida:
$ ./a.out
0x804a01c
0x804a01c
Aquí está mi pregunta:
- ¿Por qué el enlazador que implementa "int global" y "char global" es la misma variable global?
- ¿Cómo es que el compilador no se queja? (No es la advertencia más pequeña con
-Wall -Wextra -ansi
...) - Cómo se gestiona el tamaño de la variable global (el tamaño de int y char son diferentes)
PD: La segunda pregunta está relacionada con la arquitectura / compilador, así que tomemos el gcc o Visual C ++ (para C) con el tamaño int como 32 bits
EDITAR: ESTA NO ES UNA PREGUNTA PARA C ++ PERO para C!
Utilizo la versión 4.4.1 de gcc y en Ubuntu 9.10, aquí está la salida de la consola de compilación:
$ ls
global_data1.c global_data2.c global_data.c
$ gcc -Wall -Wextra -ansi global_data*.c
$ ./a.out
0x804a01c
0x804a01c
or
$ gcc -Wall -Wextra -ansi -c global_data*.c
$ gcc -Wall -Wextra -ansi global_data*.o
$ ./a.out
0x804a01c
0x804a01c
Qué compilador estás usando ¿Cuál es la plataforma? Con g ++ me sale
/tmp/cc8Gnf4h.o:(.bss+0x0): multiple definition of `global''
/tmp/ccDQHZn2.o:(.bss+0x0): first defined here
/usr/bin/ld: Warning: size of symbol `global'' changed from 4 in a.o to 1 in b.o
AFAIR, en C ++ las variables en diferentes unidades de traducción tienen exactamente la misma declaración para funcionar.
gcc
no informa ningún error / advertencia. Pero g++
hace.
EDITAR:
Parece que C permite definiciones provisionales para una variable.
En su caso, las definiciones globales son tentativas y, en ese caso, se elige la primera vista por el vinculador.
Cambie su archivo2 a:
char global = 1; // no more tentative...but explicit.
Ahora, si compila como antes, se ignorará la definición tentativa en archivo1.
Haz que tanto la def sea explícita como:
int global = 1; // in file1
char global = 1; // in file2
ahora ninguno puede ser ignorado y obtenemos el error de def múltiple.
Esto tiene que ver con algo llamado "definición tentativa" en C. En primer lugar, si asigna a global
en file1 y file2, obtendrá un error en C. Esto se debe a que global
ya no se define provisionalmente en file1 y file2, está realmente definido.
Del estándar C (énfasis mío):
Una declaración de un identificador para un objeto que tiene un alcance de archivo sin un inicializador , y sin un especificador de clase de almacenamiento o con un especificador de clase de almacenamiento estático, constituye una definición tentativa . Si una unidad de traducción contiene una o más definiciones tentativas para un identificador, y la unidad de traducción no contiene ninguna definición externa para ese identificador, entonces el comportamiento es exactamente como si la unidad de traducción contiene una declaración de alcance de archivo de ese identificador, con el tipo compuesto como del final de la unidad de traducción, con un inicializador igual a 0.
Para su caso, "unidad de traducción" (básicamente) cada archivo fuente.
Acerca de "tipos compuestos":
Para un identificador con enlace interno o externo declarado en un alcance en el que una declaración previa de ese identificador es visible, si la declaración previa especifica un enlace interno o externo, el tipo del identificador en la declaración posterior se convierte en el tipo compuesto.
Para más información sobre definiciones tentativas, vea esta pregunta y sus respuestas .
Parece que para su caso, debe ser un comportamiento indefinido porque global
se define al final de las unidades de traducción, por lo que obtiene dos definiciones de global
, y lo que es peor, son diferentes. Parece que el enlazador por defecto no se queja de esto.
GNU ld tiene una opción llamada --warn-common
, que le avisa de varias definiciones tentativas (el símbolo común es el nombre del enlazador para las variables definidas tentativamente):
$ gcc -Wl,--warn-common file*.c
/tmp/ccjuPGcq.o: warning: common of `global'' overridden by larger common
/tmp/ccw6nFHi.o: warning: larger common is here
Del manual :
Si hay solo (uno o más) símbolos comunes para una variable, va en el área de datos no inicializados del archivo de salida. El enlazador combina múltiples símbolos comunes para la misma variable en un solo símbolo. Si son de diferentes tamaños, elige el tamaño más grande. El enlazador convierte un símbolo común en una declaración, si hay una definición de la misma variable.
La opción
--warn-common
puede producir cinco tipos de advertencias. Cada advertencia consiste en un par de líneas: la primera describe el símbolo que acaba de encontrarse, y la segunda describe el símbolo anterior encontrado con el mismo nombre. Uno o ambos símbolos serán un símbolo común.