Newsgroup: it.comp.lang.c
Titolo: Dichiarazioni external e lo standard

Ciao a tutti,
vorrei delle piccole delucidazioni su alcuni punti relativi allo standard.
Basandomi su quanto scritto nello standard, ci tengo a riportare che è il
draft datato al 3 agosto 1998, vengono riportate le seguenti due
dichiarazioni:
extern int i3 = 3;
int i[];
Il modo migliore, confesso la mia ignoranza in materia, per verificare le
stesse - che a mio conto sono potenzialmente errate - è stato provare su una
delle ultime versioni del gcc - le opzioni di compilazione sono state
impostate su ISO/ANSI - ho ottenuto i seguenti errori:
    Variabile i3 is declarated with extern specifier and         at   the
same time is initialized. (per la prima)
    The ANSI C forbids this declaration. (per la seconda)

  The ANSI C forbids this declaration. (per la seconda)
Anche qui` il gcc ha ragione. Devi specificare la dimensione dell'array.
Se mi dici  in che paragrafo le hai trovate  posso controllare sulla mia
copia dello standard.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
The trouble with computers is that they do what you tell them, 
not what you want.
D. Cohen

 Kronos
Grazie Kronos.

Ciao a tutti,
mentre ci sono aggiungo una domanda: il tentativo di definizione si
riferisce solamente alla translation unit in cui è inserito, oppure ha
validità per tutti i sorgenti.
Ovvero, se io ho un file1.c con la seguente dichiarazione:
int a;
E un secondo con:
char a = 10;
Non dovrebbero entrare in contrasto sia per:
1) definizione multipla di una variabile
2) incompatibilità di tipi
Ciao e grazie.

 6.9.2 External object Definitions
[cut]
Questo dice lo standard (praticamente  uguale a quello che hai riportato
tu:
6.9.2 External object definitions 
Semantics 



4 EXAMPLE 1 


extern int i1;     // refers to previous, whose linkage is external 
extern int i2;     // refers to previous, whose linkage is internal 
extern int i3;     // refers to previous, whose linkage is external 
extern int i4;     // refers to previous, whose linkage is external 
extern int i5;     // refers to previous, whose linkage is internal 
5 EXAMPLE 2 
If at the end of the translation unit containing 
int i[];
the array i  still has incomplete type, the  implicit initializer causes
it to have one element, which is set to zero on program startup.
La cosa mi lascia molto perplesso. Dal punto 1 mi sembra di capire che
int i1 = 1;
extern int i3 = 3;
siano equivalenti, solo che nel secondo caso il linkage e` esplicito. Il
gcc 3.1 anche con -std=c99 da un warning.
L'esempio 2 al punto 5:
int i[];
e`  un 'tentative  definition',  con linkage  interno. Il  punto 3  dice
chiaramente che il tipo dell'oggetto  "shall not be an incomplete type".
Nel paragreago 6.7.5.2 punto 4 si legge "If the size is not present, the
array type is an incomplete type". gcc dixit:
warning: array `i' assumed to have one element
Sempre al punto 5 si legge che il tipo e` incompleto, ma interviene un
inizializzazione implicita (penso che si riferisca all'ultima frase del
punto 2). Penso cioe` che 
int i[];
a causa dell'inizializzazione implicita diventi
int i[] = {0};
La dimensione e` quindi dedotta dalla lista degli inizializzatori.
Mi piacerebbe  pero` avere il  parere di qualcun altro. Andrea  (uno dei
due :D) se ci sei batti un colpo.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
"La mia teoria scientifica preferita e` quella secondo la quale gli 
 anelli di Saturno sarebbero interamente composti dai bagagli andati 
 persi nei viaggi aerei." -- Mark Russel

 2) incompatibilita` di tipi
Penso  di no. Al  punto  2 del  paragrafo  citato si  legge  che le  due
dichiarazioni  dovrebbero diventare  globali  a file  scope, quindi  con
linkage interno.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Windows /win'dohz/ n. : thirty-two  bit extension and graphical shell to
a sixteen  bit patch to an  eight bit operating system  originally coded
for a  four bit microprocessor  which was  written by a  two-bit company
that can't stand a bit of competition.

 linkage interno.
Ho provato, sia sul compilatore gcc sia leggendo un terzo testo -
Programmare in C e in C++ -, dove viene specificato che in casi simili a:
file1.c
int a = 10;
file2.c
char a;
oppure a
file1.c
int a;
file2.c
char a;
la variabile - in questo caso - č allocata dal linker in base o alla
presenza dell'inizializzatore oppure in base alla definizione che occupa di
piů.
Personalmente comincia a girarmi la testa. E io che pensavo che fosse solo
compito del compilatore occuparsi dell'allocazione delle variabili... .
Ciao.

 piu`.
I due esempi sono profondamente diversi. Il primo rientra nella
descrizione data dal punto 1:
1 If the declaration  of an identifier for an object  has file scope and
an  initializer,  the declaration  is  an  external definition  for  the
identifier.
Quindi e` come se tu avessi:
--- file1.c ---
extern int a = 10;
--- end ---
--- file2.c ---
char a;
--- end ---
In questo  caso in effetti  c'e` una collisione  tra il simbolo  'a' nel
file1 che ha linkage esterno ed il  simbolo 'a' nel file2 che ha linkage
interno. Il gcc decide  di allocare spazio per contenere  il piu` grande
dei due. L'uso del programma (specie se i tipi sono incompatibili) porta
a risultati strani o ad un crash sul mio sistema:
kronos:~/c$ cat p1.c
#include <stdio.h>
void foo(void);
int a;
int main() {
        a = 5;
        printf("A = %d\n", a);
        foo();
        printf("A = %d\n", a);
}
kronos:~/c$ cat p2.c
#include <stdio.h>
double a = 3.14;
void foo(void) {
        printf("A = %f\n", a);
}
kronos:~/c$ gcc -Wall -g -op p1.c p2.c
/usr/lib/gcc-lib/i586-pc-linux-gnu/3.1/../../../../i586-pc-linux-gnu/bin/ld:
Warning: size of symbol `a' changed from 4 to 8 in /tmp/ccziGSgk.o
kronos:~/c$ p
A = 5
A = 3.139999
A = 5
Il risultato sembra ragionevole. Pero` compilando questo:
kronos:~/c$ cat p1.c
#include <stdio.h>
void foo(void);
int a = 5;
int main() {
        printf("A = %d\n", a);
        foo();
        printf("A = %d\n", a);
}
kronos:~/c$ cat p2.c
#include <stdio.h>
void foo(void) {
        a = 3.14;
        printf("A = %f\n", a);
}
kronos:~/c$ gcc -Wall -g -op p1.c p2.c
kronos:~/c$ p
A = 5
A = 3.140000
A = 1374389535
Aborted
Il programma si  becca un bel sigabort. Penso che in  entrambi i casi il
compilatore dovrebbe rifiutarsi di fare il link.
Il tuo secondo esempio e` invece valido per il punto 2:
--- file1.c ---
int a;
--- end ---
--- file2.c ---
double a;
--- end ---
e` perfettamente valido, visto che i due simboli hanno linkage interno e
non entrano in collisione.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
"L'abilita` politica e` l'abilita` di prevedere quello che
 accadra` domani, la prossima settimana, il prossimo mese e
 l'anno prossimo. E di essere cosi` abili, piu` tardi,
 da spiegare  perche' non e` accaduto."

 Aborted
Il compilatore dovrebbe darti errore in quanto nel file p2.c non hai
definito il simbolo A. Non basta definire  una variabile con linkage esterno
in un modulo se negli altri non segnali la sua presenza con una
dichiarazione.
Ciao.

 definito il simbolo A.
Errore di copy&paste.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
"Su cio` di cui non si puo` parlare e` bene tacere".
 Ludwig Wittgenstein