Sembra che la variabile globale non inizializzata sia considerata come simbolo debole in Gcc. Qual è la ragione di questo?Perché la variabile globale non inizializzata è un simbolo debole?
risposta
gcc, in modalità C:
non inizializzate globali che non sono dichiarati extern
sono trattati come simboli "comuni", non simboli deboli.
I simboli comuni vengono uniti al momento del collegamento in modo che si riferiscano tutti alla stessa memoria; se più di un oggetto tenta di inizializzare un tale simbolo, si verificherà un errore di collegamento. (Se non sono esplicitamente inizializzate ovunque, saranno messi in BSS, cioè inizializzato a 0.)
gcc, in C++ modalità:
Non lo stesso - non fa il cosa simboli comuni. I totali "non inizializzati" che non sono dichiarati extern
vengono inizializzati implicitamente su un valore predefinito (0 per i tipi semplici o costruttore predefinito).
In entrambi i casi, un simbolo debole permette un simbolo inizializzato per essere sovrascritta da un simbolo non debole inizializzato con lo stesso nome in fase di collegamento.
Per illustrare (concentrandosi sul caso C qui), userò 4 varianti di un programma principale, che sono tutti uguali tranne che per il modo in cui viene dichiarata global
:
main_init.c:
#include <stdio.h> int global = 999; int main(void) { printf("%d\n", global); return 0; }
main_uninit.c, whic h omette l'inizializzazione:
#include <stdio.h> int global; int main(void) { printf("%d\n", global); return 0; }
main_uninit_extern.c, che aggiunge la parola chiave
extern
:#include <stdio.h> extern int global; int main(void) { printf("%d\n", global); return 0; }
main_weak_init.c, che inizializza
global
e dichiara di essere un simbolo debole:#include <stdio.h> int global __attribute__((weak)) = 999; int main(void) { printf("%d\n", global); return 0; }
e another_def.c che inizializza lo stesso globale:
int global = 1234;
Utilizzando main_uninit.c
da sola dà 0:
$ gcc -o test main_uninit.c && ./test
0
ma quando another_def.c
è incluso pure, global
è esplicitamente inizializzato ed otteniamo il risultato atteso:
$ gcc -o test main_uninit.c another_def.c && ./test
1234
(Nota che questo caso fallisce invece se stai usando C++.)
Se proviamo sia con main_init.c
e another.def.c
invece, abbiamo 2 Inizializzazioni di global
, che non funzioneranno:
$ gcc -o test main_init.c another_def.c && ./test
/tmp/cc5DQeaz.o:(.data+0x0): multiple definition of `global'
/tmp/ccgyz6rL.o:(.data+0x0): first defined here
collect2: ld returned 1 exit status
main_uninit_extern.c
da sola non funziona affatto - la parola chiave extern
fa sì che il simbolo di essere un riferimento esterno ordinario piuttosto che un simbolo comune, in modo che il linker si lamenta:
$ gcc -o test main_uninit_extern.c && ./test
/tmp/ccqdYUIr.o: In function `main':
main_uninit_extern.c:(.text+0x12): undefined reference to `global'
collect2: ld returned 1 exit status
funziona bene una volta che l'inizializzazione da another_def.c
i s incluso:
$ gcc -o test main_uninit_extern.c another_def.c && ./test
1234
Utilizzando main_init_weak.c
da solo dà il valore che inizializzato il simbolo debole (999), in quanto non v'è nulla di ignorarlo:
$ gcc -o test main_init_weak.c && ./test
999
Ma tirando in in questo caso l'altra definizione da another_def.c
funziona in questo caso, poiché la definizione forte sostituisce la definizione debole in main_init_weak.c
:
$ gcc -o test main_init_weak.c another_def.c && ./test
1234
Bella risposta, grazie. Posso chiedere se si applica a C++? –
Ottima spiegazione con esempi. Potresti includere anche quanto debole interagisce con le funzioni? – Tomek
@Maciej - buon punto, ho dimenticato che questo è stato taggato con entrambi quando ho scritto la mia risposta in origine! No, non è lo stesso per C++, quindi ho aggiornato la mia risposta di conseguenza. –
È questo che intendevi?
weak.c
#include <stdio.h>
int weak; /* global, weak, zero */
int main(void) {
printf("weak value is %d.\n", weak);
return 0;
}
strong.c
int weak = 42; /* global, strong, 42 */
conduzione Esempio
$ gcc weak.c $ ./a.out weak value is 0. $ gcc weak.c strong.c $ ./a.out weak value is 42.
Il Questa è un'estensione comune, una che gcc utilizza (grazie Andrey).int weak;
in weak.c è una dichiarazione, non una definizione. Oppure potresti dire che è una definizione provvisoria. La definizione reale è strong.c
quando il file oggetto è collegato nel programma finale o in weak.c
in caso contrario.
Non vero. 'int weak' in' weak.c' è una definizione.Un tentativo, ma definizione comunque. Il programma sopra * non * viola le regole della lingua, tuttavia è supportato come un'estensione non standard. – AnT
Qualsiasi definizione multipla di un simbolo globale è un comportamento non definito, quindi gcc (o meglio il linker GNU binutils) è libero di fare ciò che vuole. In pratica, segue il comportamento tradizionale per evitare di rompere il codice che si basa su questo comportamento.
Vuoi dire più ** definizione **? – pmg
Sì, aggiustandolo. –
La domanda è basata su una premessa errata. Le variabili globali non inizializzate non sono simboli deboli.
Apparentemente la domanda si riferisce alla capacità di definire lo stesso oggetto non inizializzato con il collegamento esterno in più unità di traduzione. Formalmente, non è permesso - è un errore sia in C che in C++.Tuttavia, almeno in C è riconosciuto dalla norma C99 come "Estensione comune" del linguaggio, implementata in molti compilatori della vita reale
J.5 estensioni comuni
J.5.11 multipla esterna definizioni
ci possono essere più di uno esterno definizione per l'identificatore di un oggetto , con o senza l'esplicito utilizzo della parola chiave extern; se le definizioni non sono d'accordo, o più di una è inizializzata, il comportamento è indefinito (6.9.2).
Nota: contrariamente alla credenza popolare, il linguaggio C proibisce esplicitamente l'introduzione di più definizioni di entità con collegamento esterno nel programma, proprio come fa il C++.
6.9 Definizioni esterne
Una definizione esterna è una dichiarazione esterna che è anche una definizione di una funzione (diverso una definizione di linea) o un oggetto. Se un identificatore dichiarato con esterna collegamento viene utilizzato in un'espressione (a titolo non dell'operando di un operatore sizeof cui risultato è una costante intero), in qualche parte l'intero programma vi sarà esattamente uno definizione esterna per l'identificatore ; in caso contrario, deve essere non più di uno.
Tuttavia, l'estensione che consente questo è stato molto popolare con molti compilatori C, di cui GCC è semplicemente uno.
Per implementare i blocchi comuni di FORTRAN è richiesta la funzione di linker di supporto. Si noterà che GCC include un compilatore FORTRAN nella raccolta. Poiché le librerie di supporto sono implementate in C, non sorprende che ci sia una piccola quantità di perdite innocue dal linker. – RBerteig
Puoi dare un esempio di definizione esterna e dichiarazione esterna? – Thomson
Non sono solo FORTRAN, anche le funzioni inline C++ e i modelli implicitamente istanziati sono deboli. – MSalters
- 1. Perché la mia variabile extern non è ancora inizializzata?
- 2. perché una variabile di constexpr non inizializzata non è costante?
- 3. Perché la variabile 'angolare' globale è stata rimossa da angularjs.TypeScript.DefinitelyTyped?
- 4. La variabile debole debole di Swift non verrà compilata
- 5. Perché la variabile const non deve essere inizializzata in C?
- 6. NetBeans "La variabile $ out sembra non inizializzata"
- 7. Interruttore dichiarazione variabile non inizializzata
- 8. variabile globale non ha portata globale
- 9. Perché javac si lamenta della variabile non inizializzata?
- 10. perché il blocco catch genera un errore con la variabile non inizializzata in Java
- 11. Variabile globale C++ non inizializzata quando collegata tramite librerie statiche, ma OK quando compilata con l'origine
- 12. Linker Apple Mach-O Avviso accesso diretto in ... a simbolo globale debole
- 13. Variabile non inizializzata Java con curiosità finale
- 14. Ruby "variabile di istanza non inizializzata" avvertimento
- 15. Se una variabile globale è inizializzata su 0, passerà a BSS?
- 16. La variabile "snackbar" potrebbe non essere stata inizializzata
- 17. Quanto è sicuro l'utilizzo. = Operatore su una variabile non inizializzata?
- 18. La variabile Delphi potrebbe non essere stata inizializzata con avviso
- 19. la ricorsione non funziona senza dichiarare la variabile globale
- 20. Python globale variabile non aggiornare
- 21. Riferimento alla variabile globale da un modulo
- 22. Perché non posso impostare una variabile globale in Python?
- 23. Come verrà inizializzata questa variabile?
- 24. Perché è necessario passare argomenti a una funzione autoesecutiva in javascript se la variabile è globale?
- 25. PrintNormal() Edizione 'Non è inizializzata'
- 26. Mocking una variabile globale
- 27. Timeit, NameError: il nome globale non è definito. Ma non ho usato una variabile globale
- 28. 'Inizializzatore non costante' sulla variabile globale?
- 29. CodeIgniter variabile globale
- 30. Nessuna inizializzazione globale variabile
codice di esempio – pmg
Come vieni a questa conclusione, cosa hai provato, quali sono i fatti? –
C o C++? C'è una grande differenza. –