2013-06-28 15 views
5

Prima di tutto, per favore aiutami a trovare un titolo migliore che descriva la situazione in modo più accurato. Ho creato la seguente versione semplificata di un problema in cui mi sono imbattuto durante il debug di codice (incorporato) reale.Variabili globali non inizializzate di diverso tipo ma con lo stesso nome - strano comportamento del collegamento

Si consideri il seguente codice di file di t1.c:

#include <stdio.h> 

int A; 

void f() { printf("%d\n", A); } 

extern void g(); 

void main(void) 
{ 
    g(); A=1; g(); 
    A++; 
    f(); 
} 

e il codice di t2.c:

#include <stdio.h> 

double A; 

void g() 
{ 
    A += 1.0; 
    printf("%f\n", A); 
} 

Ora compilare ed eseguire il codice come questo:

gcc -Wall t1.c t2.c -o t && ./t 

1.000000 
2.000000 
1 

Nota che entrambi i file contengono una variabile globale chiamata A che ha un tipo diverso. Mi aspettavo un errore di collegamento perché il simbolo A esiste più volte.

Io in realtà ottenere un link di avvertimento (modifiche di dimensione oggetto in diversi .o), quando ho inizializzare una delle due variabili, un errore (più definizioni) quando ho inizializzo entrambi.

Ho provato questo con gcc 4.7 e 4.4.

È questo comportamento previsto? Se è così, c'è qualcosa che posso fare per istruire la toolchain (basata su gcc) per avvisare su di esso?

È un bug?

risposta

4

Sì, compilare con -fno-common opzione per ottenere l'errore di linker:

$ gcc -Wall -fno-common -c t1.c 
$ gcc -Wall -fno-common -c t2.c 
$ gcc t1.o t2.o -o t 
t2.o:t2.c:(.bss+0x0): multiple definition of `_A' 
t1.o:t1.c:(.bss+0x0): first defined here 
collect2: error: ld returned 1 exit status 
$ 

Se si vuole compilare questo in una sola riga si può anche passare il --warn-common al linker (qui con --fatal-warnings per avere un errore invece di un avvertimento):

$ gcc -Wl,--fatal-warnings,--warn-common -Wall t1.c t2.c -o t 
/tmp/cc1xQo79.o: warning: common of `_A' overriding smaller common 
/tmp/ccLnhxoe.o: warning: smaller common is here 
collect2: error: ld returned 1 exit status 
$ 

Per impostazione predefinita gcc esegue varie ottimizzazioni di C comportamenti indefiniti come estensione. C consente a qualsiasi implementazione di interrompere la traduzione in presenza di tale programma, quindi, salvo se si hanno ottime ragioni per farlo, è necessario evitarlo.

+0

Grazie per la risposta: non ero a conoscenza del fatto che i globali non inizializzati entrano nel cosiddetto * comune * blocco. –

1

Per rispondere alla risposta di @ ouah, penso che il motivo per cui è solo un avvertimento è perché è una variabile non inizializzata, quindi va nella sezione .bss. Iniziando le variabili, il compilatore le sposta nella sezione .data - il fatto che la sovrapposizione di .bss sia solo un avvertimento potrebbe essere una stranezza di gcc, però.

+0

La sezione non ha importanza: le variabili inizializzate in modo esplicito con zero creano una definizione normale (non comune) ma finiscono comunque in '.bss'. – jilles

Problemi correlati