C dice che è un comportamento non definito.
(C99, 6.9p5) "Se un identificatore dichiarato con collegamento esterno è utilizzato in un'espressione (non come parte della operando di un operatore sizeof cui risultato è un numero intero costante), da qualche parte in tutto il programma vi saranno esattamente una definizione esterna per l'identificatore, altrimenti non ci sarà più di un"
essere comportamento indefinito significa un linker può interrompere il processo di collegamento in presenza di più definizioni di oggetti esterni.
Ora linker sono belle (o male, è possibile scegliere) e di solito hanno estensioni predefinite per gestire molteplici definizioni di oggetto esterno e non fallire in alcuni casi.
Se si utilizza gcc
e ld
da binutils, si otterrà un errore se i due oggetti sono inizializzati in modo esplicito. Ad esempio, hai int x = 0;
nella prima unità di traduzione e double x = 0.0;
.
Altrimenti, se uno degli oggetti esterni non è inizializzato esplicitamente (la situazione nell'esempio) gcc
combina silenziosamente i due oggetti in un unico simbolo. Puoi comunque chiedere al linker di segnalare un avviso passandogli l'opzione --warn-common
.
Per esempio, quando il collegamento dei moduli:
gcc -Wl,--warn-common module1.o module2.o
per ottenere il processo di collegamento interrotta, è possibile richiedere il linker per il trattamento di tutti gli avvisi come errori utilizzando --fatal-warnings
opzione (-Wl,--fatal-warnings,--warn-common
).
Un altro modo per interrompere il processo di collegamento è utilizzare l'opzione del compilatore -fno-common
, come spiegato da @teppic nella sua risposta. -fno-common
proibisce agli oggetti esterni di ottenere un tipo di simbolo comune durante la compilazione. Se lo fai per entrambi i moduli e poi link, riceverai anche l'errore di linker a definizione multipla.
gcc -Wall -fno-common -c module1.c module2.c
gcc module1.o module2.o
Quindi, in questo caso c'è solo una "x" nella tabella dei simboli? Posso vedere alcuni bug strani derivanti da quello. Thx – amorimluc
@amorimluc nel tuo caso è probabile che ti piaccia ottenere un errore dal linker o da un singolo oggetto nel binario finale e il tuo programma invocherà un comportamento indefinito. – ouah
Pensavo di sì, ma si compila e si collega bene. E x è stampato come int ma con il modello di bit del float 3.14. Questo probabilmente non succede molto nella vita reale, ma sarebbe sicuramente difficile trovare questo sottile bug in un grande programma ... – amorimluc