2010-02-25 16 views
17

Cuando escribo el siguiente programa:aplicación Variable global

archivo 1: archivo

#include <stdio.h>  
int global;  
void print_global1() { 
     printf("%p\n", &global); 
} 

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; 
} 

de salida:

$ ./a.out 
0x804a01c 
0x804a01c 

Aquí es mi pregunta:

  • Por qué están implementando el enlazador "int global" y "char global" como la misma variable global:
  • ¿Cómo es que el compilador no se queja (no el más pequeño de advertencia con -Wall -Wextra -ansi ...)
  • ¿Cómo están el tamaño de la variable global gestionado (el tamaño de int y carbón son diferentes)

PS: La segunda pregunta es arquitectura/compilador relacionado, 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 versión de gcc 4.4.1 y en Ubuntu 9.10, aquí está la salida de la consola 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 

Respuesta

12

gcc no notifica ningún error/advertencias. Pero g++ hace.

EDIT:

Parece C permite tentative definitions para una variable.

En su caso, ambas definiciones globales son tentativas y, en ese caso, se elige la primera vista por el vinculador.

Cambiar la fichero2 a:

char global = 1; // no more tentative...but explicit. 

Ahora bien, si se compila como antes, la definición tentativa en archivo1 será ignorado.

hacer que tanto la definición explícita por:

int global = 1; // in file1 

char global = 1; // in file2 

ahora no puede ser ignorado y que sale el error def múltiple.

+0

No estoy haciendo C++ pero el programa C (es por eso que no puse la bandera C++ en mi respuesta)! Parece que la especificación estándar C permite este comportamiento (pero no estoy seguro). Todavía puedo usar el enlazador C++ para verificar si hay definición múltiple, pero no estoy seguro si es realmente seguro ... – Phong

+0

@Phong: tienes razón ... la C std lo permite. He actualizado mi respuesta. – codaddict

+0

@codaddict: +1, ¡Gracias por la actualización rápida! Ahora entiendo mejor cómo lo maneja el compilador. – Phong

1

Qué compilador está usando. ¿Cuál es la plataforma? Con g ++ Puedo obtener

/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 tanto tienen exactamente la misma declaración a trabajar.

1

El enlazador permite tener datos externos duplicados como este (aunque me sorprende que los diferentes tipos no causen ningún problema). El que obtengas depende del orden de tus archivos objeto en tu línea de comando de enlace.

+0

+1 ¿Existe alguna herramienta que me permita conocer el tamaño de la variable "global"? – Phong

5

Esto tiene que ver con algo que se llama "definición tentativa" en C. En primer lugar, si se asigna a global tanto en archivo1 y archivo2, se obtiene un error en C. Esto se debe a global no está tentativamente define en archivo1 y file2 más, está realmente definido.

de la norma C (énfasis mío):

Una declaración de un identificador para un objeto que tiene presentar alcance sin un inicializador, y sin un especificador de clase de almacenamiento o con la clase de almacenamiento especificador 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 de origen.

Acerca de "tipos de compuestos":

para un identificador con enlace interno o externo declarado en un ámbito en el que una previa declaración de ese identificador es visible, si la declaración previa especifica enlazado externo interna o , el tipo del identificador en la declaración posterior se convierte en el tipo compuesto .

Para obtener más información sobre definiciones tentativas, consulte this question and its answers.

Parece que para su caso, debe ser un comportamiento no definido 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 advierte de múltiples definiciones tentativas (símbolo común es el nombre del enlazador para las variables tentativamente definidos):

$ 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 

Desde el manual:

Si hay son solo (uno o más) símbolos comunes para una variable, van 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.

+0

@alok: +1 Gracias por enseñarme la opción -Wl, - warn-common gcc. – Phong