Newsgroup: it.comp.lang.c
Titolo: Perché serve la keyword extern?

nel senso che se ho bisogno di una variabile contenuta in un altro 
modulo, mi basta includere il file .H di quel modulo, no? Quindi, perché 
mi serve poter dichiarare variabili "extern" se posso includere il file 
.H in cui sono definite?
 
Oppure c'è qualcosa che mi sfugge? O_O


La seconda che hai detto. ;)
 
Per dirla in modo breve e impreciso, il preprocessore C *inserisce 
letteralmente* il testo del file .H nel punto del file .C che lo 
include.
 
Quindi senza specificare extern avresti N copie della 
stessa variabile (una per ogni file .c che include il .h in questione)
quindi ogni file accederebbe alla sua copia privata invece che a
quella "condivisa". 
 
Mettendo extern dici al linker di non riservare
lo spazio di memoria per la variabile ma di collegarti allo spazio
in qualche altro file 
 
Infatti in almeno uno la variabile andra poi definita senza extern 
altrimenti ti esce un errore in fase di link
 
ciao
Giacomo
 
 
 
 
 
 
 

 quella "condivisa".
 
Ah, ecco... quindi usare extern serve per avere variabili globali.

 quella "condivisa".
Non dovrebbe essere cosi', a meno che le variabili non siano dichiarate
static, infatti i tag con visibilita' globale sono per default
'extern', vedi 6.2.2 Linkages of identifier (C99).
Questo vale sia per le funzioni che per le variabili :-)
Cio' non significa che extern non deve essere usato, anche per
migliorare la lettura e manutenzione del codice!
IMHO, dichiara le variabili in un file .c e usa l' extern
esplicitamente nei file .h, e vivrai felice...
 
"If the declaration of an identifier for a function has no storage-class 
specifier, its linkage is determined exactly as if it were declared with 
the storage-class specifier extern.
If the declaration of an identifier for an object has file scope and no 
storage-class specifier, its linkage is external."
 
a.

 Ah, ecco... quindi usare extern serve per avere variabili globali.
 
No. Essere una variabile globale dipende da dove dichiari una 
variabile. Se la dichiari in un blocco o funzione la variabile sarà
locale, se la dichiari fuori da ogni vlocco o funzione sarà globale.
Le parole chiave extern e static per le variabili globali e le 
funzioni influiscono sul fatto di essere pubbliche o private. Una 
variabile globale od una funzione di tipo static saranno private e 
quindi visibili solo all'interno della unita di compilazione in cui 
sono dichiarate, altrimenti saranno pubbliche e quindi accessibili e
visibili in tutto il programma.
 
 

 altrimenti ti esce un errore in fase di link
 
Questo è punto importante. ANSI C dice di mettere extern in tutte le
unità di compilazione tranne in una dove non si deve mettere extern.
Ma questo è  solo un modo di evitare al linker le situazioni ambigue
 
Prima situazione: dichiari una variabile senza la parola chiave 
  extern in tutti i sorgenti. 
In questa situazione il linker decide di allocare tante copie della 
variabile, una per ogni unità di compilazione. Ma potrebbe anche
allocare una sola copia della variabile e la situazione sarebbe lo
stesso non ambigua.
 
Seconda situazione dichiari una variabile usando la parola chiave 
  extern in tutti i sorgenti. 
Anche questo caso non c'è nessuna ambiguità. per ANSI C il linker deve
generare un messaggio di errore ma un linker potrebbe benissimo mettere
la variabile nel segmento dati,  nel segmnento BSS, nello stack o dove
vuole mantenendo un comportamento coerente.
 
PS Il comportamento definito dallo standard mi pare poco logico. È un 
comportamento dettato da buone ragioni ma poco logico.
 
Terza situazione: dichiari una variabile con extern in due o più 
  sorgenti e senza extern in alcuni altri.
Questo è l'unico caso ambiguo. Questo è l'unico caso dove il linker
dovrebbe fermarsi con un errore.
 
 

 locale, se la dichiari fuori da ogni vlocco o funzione sarà globale.
 
Cioè ogni file .c vede automaticamente tutte le variabili definite fuori 
da ogni funzione o blocco in tutti gli altri file .c?
 
Quindi se io in pippo.c dichiaro una variabile fuori da ogni funzione o 
blocco, poi posso usarla in pluto.c senza doverci scrivere "extern 
nomevar ecc. ecc."?
 


perchè i linker moderni  tentano di risolvere l' eventuale conflitto
 
ES:
 
f.c
int glob;
int f() { return ++glob; }
 
main.c
#include <stdio.h>
int glob=5;
int f();
 
int main() { f();printf("%d\n",glob); return 0;}
 
 
qui abbiamo un conflitto; la variabile glob è dichiarata due volte
ma compilando non si hanno errori e funziona; almeno senza  ottimizzazioni
 
gcc f.c main.c
 
il linker si accorge del conflitto ed elimina la dichiarazione di glob 
in f.c perchè la glob di main.c è inizializzata
 
con  un altro linker l' esecuzione potrebbe dare altri risultati oppure 
segnalare un errore i n fase di linking
 
compilando con O3 (massime ottimizzazioni) si ha:
 
gcc -O3 f.c main.c
 
/usr/bin/ld: Warning: alignment 4 of symbol `glob' in /tmp/ccs97CSq.o is 
smaller than 16 in /tmp/ccGxHXRg.o
 
 
la procedura corretta dovrebbe essere:
 
f.c
extern int glob;
int f() { return ++glob; }
 
e compilando con
gcc -O3 f.c main.c
 
 
non si hanno warning
 
questi esempi sono stati effettuati con gcc 4.5.2 piattaforma x86_64
 

 nomevar ecc. ecc."?
 
Non ho capito bene. Facciamo che usi gcc.
Nel file pippo.c dichiari una variabile cosi:
 
int variabile;
 
Nel file pluto.c dichiari la varibile così:
 
extern  int variabile:
 
Per le funzioni la storia è simile.
Nel file pippo.c dichiari la funzione così:
 
int funzione(int argomento);
 
e la definisci così:
 
int funzione(int argomento)
  {
      istruzioni
  ]
 
(In realtà basta solo la definizione, la dichiarazione è facoltativa).
 
Nel file pluto.c invece dichiari solo la funzione perché è già
definita altrove.
 

 extern  int variabile;
 
Ops mi è  partito il dito. Ho omesso la cosa più importante:
nel file pluto.c la parola extern è opzionale.

 in f.c perchè la glob di main.c è inizializzata
 
Alt! Il linker non fa niente di questo perché nelle dichiarazioni non
si genere nessun codice. Semplicemente il linker vede che nelle 
tabelle dei simboli dei programmi oggetto c'è la stessa variabile e
quindi mette la stessa locazione di memoria nei due diversi 
riferimenti. Inoltre, poiché nel secondo file oggetto la variabile è 
inizializzata e quindi già definita, usa il riferimento preso dal 
secondo file oggetto e non alloca altra memoria.
 
 

 usare la dichiarazione extern
 
Non è del tutto corretto.  Io preferisco mettere la keyword 'extern' 
per una migliore documentazione e chiarezza.  È facoltà del 
compilatore rendere usabili esternamente tutto quanto non sia 
esplicitamente definito locale (variabili definite all'interno di 
funzioni, di blocchi o definite 'static'.
 
E credo che sia una caratteristica di quasi tutti i compilatori 
moderni.  L'ultimo compilatore che non faceva questo eta il Lattice 
dell'82 che usavo sul mio primo XT.
 
Ciao
Giovanni
-- 
   A computer is like an air conditioner,
   it stops working when you open Windows.
   < 
http://giovanni.homelinux.net/
 >
 

 secondo file oggetto e non alloca altra memoria.
 
Ottimo, la precisazione è fatta
Tirando le somme per avere la massima portabilità e seguire gli standard
occorre una sola definizione ed n dichiarazioni extern
 
 
 

 occorre una sola definizione ed n dichiarazioni extern
 
Proprio questo non i sento di sottoscrivere: questo comportamento è
una buona pratica di programmazione ma è solo una convenzione, non
è dettata da nessuno standard, non influisce sulla portabilità del 
codice.
 


Lo standard dice questo:
When declaring a global function or variable in a header file, use an 
explicit extern. For functions, provide a full ANSI C prototype. For 
example:
 
extern int errno;
extern void free(void *);
 
E si,  anche per le funzioni
 
E poi dice
 
Why the extern? It is OK to declare an object any number of times, but 
in all the source files there can be only one definition. The extern 
says ``This is only a declaration.'' (A definition is something that 
actually allocates and initializes storage for the object.) Historically,
 
int foo;
was ambiguously treated as either a declaration or both declaration and 
definition depending on linker magic.
 
 
 
 

 definition depending on linker magic.
 
Ecco. Questa è una dichiarazione di una variabile esterna e come 
tale deve essere trattata: se il compilatore fa cose strane sbaglia
e si deve adeguare allo standard.
 
Il problema nasce dal fatto che alcuni compilatori, in funzione 
del modello di memoria, del modello di codice da generare, dalle 
direttive di compilazione, trattano questa istruzione come fosse:
 
int foo=0;
 
oppure
 
int foo=$RANDOM;
 
per cui anticipano la definizione alla fase di compilazione. Un 
momento. Parliamoci chiaro: o questa deve essere una variabile 
privata e va bene inizializzarla  e definirla, ma in questo caso 
bisogna usare la parola chiave static. Oppure deve essere globale
(con tutti i problemi che comportano le varibili globali) e 
quindi di tipo extern e la sua definizione deve essere lasciata 
al linker. In entrambi i casi il compilatore sbaglia.
Ed in entrambi i casi il compilatore non rispetta lo standard e 
deve cambiare adeguarsi e non deve essere che lo standard si deve
adeguare al compilatore.
 
Quindi lo standard fa notare questo e prende delle precauzioni per
colmare una lacuna. Però a mio avviso sbaglia perché oltre a dare 
consigli dovrebbe regolare il comportamento dei compilatori e non 
adeguarsi agli errori che fanno questi ultimi.
 
 
 
 
 

 Certo e stai viaggiando intorno al sei meno meno. ;-)
 
Secondo tè devo discutere sulla differenza tra dichiarazione e definizione ?
Parlane tu se vuoi, il sottoscritto non si mette a discutere di simili 
banalità; roba da neofita del C insomma

Quale problema ?

Lo standard avrebbe dovuto affermare
int a;
nello scope globale è automaticamente extern ?
 
Sarebbe logico ma non lo ha fatto
Probabilmente alla fase di stesura hanno dovuto fare dei compromessi
con la realtà esistente

 nello scope globale è automaticamente extern ?
 
Fin dalle prime implementazioni è cosi, la parola chiave estern è 
sempre stata facoltativa fino a rtempoi recenti e tutti gli standard, 
il K&R, l'ANSI e i vari Cxx fino al C99 dicono hhe le variabili 
globali sono automaticamente extern. Da cui la domanda dell'OP.
 
plonk


Assolutamente non vero
Ho preso il 
draft(
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf
) e non 
dice niente di questo