In condizioni normali (nessun flag gcc in più) si dovrebbe andare bene per compilare il codice come:
gcc file1.c file2.c
Che cosa sta per accadere è il compilatore vedrà che ci sono due variabili globali chiamato la stessa cosa e nessuno dei due è inizializzato. Quindi posizionerà le variabili globali non inizializzate nella sezione "comune" del codice **. In altre parole, avrà solo una copia della "prima" variabile. Questo accade perché il valore predefinito per gcc
è -fcommon
Se si dovesse compilare con la bandiera -fno-common
si sarebbe ora visualizzato l'errore stavi pensando di:
/tmp/ccZNeN8c.o:(.bss+0x0): multiple definition of `first'
/tmp/cc09s2r7.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status
Per risolvere questo ci si aggiunge a extern
tutti tranne una delle variabili.
ATTENZIONE:
Ora diciamo che hai avuto due array non inizializzate globali di diverse dimensioni:
// file1.c
int first[10];
// file2.c
int first[20];
Beh indovinate un po ', li compila con gcc -Wall file1.c file2.c
produce senza avvisi o errori e la variabile è stato reso comune anche se è di dimensioni diverse !!!
//objdump from file1.c:
0000000000000028 O *COM* 0000000000000020 first
//objdump from file2.c:
0000000000000050 O *COM* 0000000000000020 first
Questo è uno dei pericoli delle variabili globali.
** Se si guarda a un objdump
dei file * .o (è necessario compilare con gcc -c
per generarli) vedrete first
collocato nella sezione comune (*COM*
):
[email protected]:~/C$ objdump -t file2.o
a.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 file2.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .rodata 0000000000000000 .rodata
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000004 O *COM* 0000000000000004 first
0000000000000000 g F .text 0000000000000039 main
0000000000000000 *UND* 0000000000000000 f
0000000000000000 *UND* 0000000000000000 printf
quando si dichiara la funzione come extern, quindi il linker lo cercherà in un altro oggetto. Altrimenti lo cercherà nello stesso file. – kofemann
Questo non dovrebbe nemmeno collegare. Sei sicuro di mostrare tutti gli avvisi del compilatore e del linker? –
@KerrekSB Collegamenti perfettamente soddisfacenti con GCC. La stampa di '& first' da' f' e 'main' produce lo stesso indirizzo. –