Newsgroup: it.comp.lang.c++
Titolo: Array e puntatori

Cari amici, tempo fa su FidoNet ho avuto una lunga discussione nella
quale sostenevo che array e puntatori in C/C++ sono due oggetti
decisamente diversi mentre quasi tutti i miei interlocutori davano per
scontato che fossero esattamente la stessa cosa.
Qual'è il vostro punto di vista al riguardo?
EMG

C'e' parecchia confusione al riguardo...
Brevemente, "puntatore a T" ed "array di T" corrispondono a due tipi
differenti; nella dichiarazione, char *x riserva un'unica porzione di
memoria da usare per l'indirizzo di un carattere ed a cui riferirsi
col simbolo "x", mentre char y[42] riserva spazio contiguo sufficiente
ad ospitare 42 caratteri.  Dopo queste dichiarazioni, x non punta a
nessun carattere in particolare: deve essere inizializzata, e, dopo
che questa operazione e' stata effettuata, potra' contenere
l'indirizzo di qualsiasi carattere (che esso faccia parte di un array,
o no - e, nel primo caso, qualunque siano le dimensioni dell'array
stesso); oppure garbage (ad esempio l'indirizzo di una memoria che non
appartiene al tuo eseguibile); oppure NULL.
La memoria che corrisponde alla variabile y puo' essere anch'essa
inizializzata, ma le sue dimensioni ed il suo indirizzo non possono
essere cambiate.
La confusione sorge perche' sotto alcune circostanze puntatori ed
arrays sono "equivalenti" (non "uguali"); piu' precisamente il nome di
un array e' definito equivalente all'indirizzo del suo primo elemento,
a meno che 1) non sia l'argomento di uno degli operatori "sizeof" o
"&" (&y e' l'indirizzo dell'array y, non l'indirizzo dell'indirizzo
del primo elemento di y) o 2) come prima detto, nella dichiarazione.
Come effetto di questa equivalenza, ad esempio, se il nome di un array
compare nel richiamo di una funzione quello che viene passato alla
funzione non e' l'intero array: ma l'indirizzo del suo primo elemento.
Un'altra differenza e' che un array non puo' essere oggetto di
operazioni di assegnazione: e' infatti, in gergo, un "lvalue
_non_modificabile_".  Dopo la dichiarazione char y[42] non puoi
scrivere y="Ciao mamma" per mettere i caratteri che ti garbano nella
memoria che corrisponde ad y; devi usare strcpy(y, "Ciao mamma") o
inizializzare y nella dichiarazione stessa: char y[42]="Ciao mamma".
La differenza tra i due modi e' che, anche se le prime dieci locazioni
dell'array conterranno sempre i caratteri 'C', 'i', 'a', 'o', ' ',
'm', 'a', 'm', 'm', 'a' e l'undicesima il terminatore '\0', nel
secondo modo le restanti locazioni vengono riempite di zeri ('\0';
nell'inizializzazione di un array, quando dai un numero di costanti
minore della dimensione le restanti vengono implicitamente assunte
come tutti-i-bit-zero) mentre nel primo conservano il loro valore
precedente; nel caso di una variabile auto non precedentemente
inizializzata conterranno garbage.
-- 
Maurizio Loreti                      
http://wwwcdf.pd.infn.it/~loreti/mlo.html
Un. of Padova, Dept. of Physics - Padova, Italy          
lor...@padova.infn.it

 scontato che fossero esattamente la stessa cosa.
Sono _cose_ ben diverse (non "oggetti" nel senso dell'OO...!-).
I tuoi interlocutori sono probabilmente (e comprensibilmente)
confusi dal fatto che, usato in una espressione o passato come
parametro a una funzione, un array normalmente "decade" a
un puntatore al suo primo elemento; idea particolarmente
barbina, che il C++ eredita dal C, ma e` in C++ estremamente
pericolosa...:
    class Pippo {
    public:
        int x;
        Pippo(int x=23): x(x) {}
    };
    class Pluto: public Pippo {
    public:
        int y;
        Pluto(int x=12, int y=34): Pippo(x), y(y) {}
    };
    void funza(Pippo* p, int n, int valore);
    void disastro() {
        Pluto arrayPluti[23];
        funza(arrayPluti, 23, 45);
        // ecc ecc
    }
    void funza(Pippo* p, int n, int valore) {
        for(int i=0; i<n; ++i)
            p[i].x += valore;
    }
 
Questo "dovrebbe" aggiungere 45 a tutte le
componenti x degli oggetti dell'array, ma in realta`
combinera` un pastrocchio (probabilmente
aggiungendo 45 a varie componenti x _e y_
di una meta` circa degli oggetti dell'array).  E
non c'e` NESSUNA "violazione di tipo" da un
punto di vista formale... in un normale ambiente
di compilazione separata, e` virtualmente impossibile
per un compilatore C++ dare anche solo un warning
su questo idioma disastroso.
La radice del male e` nell'errore concettuale del
"decadere automatico" array->puntatore (che,
ahime`, il C++ non puo` togliersi, per necessita`
di compatibilita` con il C, sigh).
Soluzione: *NON* usare gli array!  std::vector<>
non e` soggetto a questo problema: un "vettore
di Pippo" NON e`-un "vettore di Pluto", anche se
un Pippo e`-un Pluto.  Se la funza e` scritta come
template puo` accettare *correttamente* un vettore
di Pippo (o di Pluto, o di qualsiasi altra classe che
offra un membro x a cui si puo` aggiungere un int);
se vogliamo vincolarla ad accettare SOLO vettori
di Pippo, dara` appunto giustamente errore quando
cerchiamo erroneamente di passarle invece un
vettore di Pluto.
I puntatori hanno "pieno diritto di cittadinanza" nella
programmazione C++; gli array, NO, e vanno usati
solo in condizioni MOLTO particolari, quando ci sono
ragioni specifiche per non usare std::vector<>, come:
    -- sto *implementando* la libreria standard del C++
        (cosa che si spera succeda di rado:-);
    -- la sto *estendendo* a scopi specifici (+ frequente);
    -- devo disporre di una tabella inizializzata in modo
        statico con certi valori predefiniti (l'array lo permette, 
        il vector no)
    -- sono in un punto assolutamente cruciale per le
        prestazioni del mio sistema (inner loop, hot-spot),
        e ho empiricamente determinato che la minuscola
        differenza di prestazioni fra array e vector, con la
        implementazione della libreria standard che io uso,
        e` fondamentale perche` il mio programma soddisfi
        i vincoli relativi alle sue prestazioni
Da notare che, anche nel quarto caso, non usero` mai
un "array nudo", bensi` lo "vestiro`" decentemente con
un ragionevole contenitore (caso 2); il caso tipico...:
template<typename T, int N>
class Array {
    T data[N];
public:
    typedef T* iterator;
    typedef const T* const_iterator;
    typedef T& reference;
    typedef const T& const_reference;
    typedef T value_type;
    T* begin() { return data; }
    T* end() { return data+N; }
    const T* begin() const { return data; }
    const T* end() const { return data+N; }
    T& operator[](int n) { return data[n]; }
    const T& operator[](int n) const { return data[n]; }
    int size() { return N; }
    // eventuali ctor, swap(), assignment, ecc ecc
};
Un "Array<Pluto,23> ar;" deve ora avere identiche
caratteristiche di prestazioni a "Pluto ar[23];", ma con
tutte le comodita` tipiche dei contenitori della libreria
standard C++ per l'uso in generic programming e senza
i tipici trabocchetti e inciampi tipici dell'uso di un costrutto
di bassissimo livello, quale e` l'array built-in in C++.
(_Da notare_: se un array deve avere dimensione non
nota a compile-time, allora le prestazioni di std::vector
non dovrebbero mai poter essere inferiori a quelle di
un array built-in dinamicamente allocato; e` solo per array
di dimensione fissa, e che vivono in stack o spazio di
memoria statica e non in heap, che potrebbe esserci un
minuscolo vantaggio a usare Array<> invece che non
std::vector<>).
Similmente, i puntatori possono a volte in C++ essere
fruttuosamente sostituiti con template detti "puntatori
furbi" (la libreria standard ne fornisce solo uno specifico,
molto efficiente per i casi specifici per i quali e` progettato:
std::auto_ptr<>).  Tuttavia, e` decisamente normale che
vi sia anche occasione di usare "puntatori nudi", quando
non si hanno esigenze speciali, mentre l'uso degli "array
built-in nudi", come spero di avere indicato, e` rarissimo
(o meglio, *dovrebbe* esserlo:-) in C++ Standard.
Alex

 scontato che fossero esattamente la stessa cosa.
Mi sembrava che alla fine si fosse convenuto che a livello SUPERIORE ossia
di C/C++ fossero due cose diverse, date le specifiche del linguaggio...,
mentre poi.. andando a spulciare l'ASM che ne veniva fuori.... array e
puntatori vengono trattati allo stesso modo...:)
Ma ci eravamo stati sopra mesi e mesi!!! :)
Perche' ricominciare? :)
Non ti "fidi" dei Fidonettiani? :))))))
Ciao,
   Silvio

 Qual'è il vostro punto di vista al riguardo?
Beh, non e` tanto questione di punti di vista...
Arrays e puntatori (nel senso di variabili di tipo puntatore) SONO due oggetti
decisamente diversi in C e in C++.
L'unica cosa che li puo` far ritenere da qualcuno "la stessa cosa" e` che
l'identificatore dell'array rappresenta il puntatore al primo elemento
dell'array, ma anche da questo punto di vista sussiste la grossa differenza che
questo puntatore e` una costante, legata a un'area di memoria allocata nel
contesto della creazione dell'array, mentre una variabile puntatore e`, appunto,
una variabile, cioe` puo` essere riassegnata per puntare a qualunque locazione
di memoria.
Saluti
Paolo

 appartiene al tuo eseguibile); oppure NULL.
L'obiezione dei miei interlocutori a quanto hai detto è che
semanticamente non vedono alcuna differenza tra un array e un puntatore
costante (const T * ). Tutto il resto per loro sono sottigliezze
sintattiche ma la realtà, dicono, è che l'array è implementato come
puntatore costante al primo elemento. Sono d'accordo, ma anche la
sintassi ha la sua importanza. Un linguaggio è fatto anche di quella.
EMG

 Non ti "fidi" dei Fidonettiani? :))))))
No, non è quello. Siccome ho visto che in questo newsgroup ci sono
persone con le palle non quadrate ma ipercubiche, ho pensato bene di
porre anche qui la questione.
EMG

 pericolosa...:
Bellissimo esempio! Se ho capito bene dipende dal fatto che l'aritmetica
dei puntatori dà risultati diversi se applicata ad un puntatore alla
classe base o alla classe derivata. Giusto?
Comunque, a quello che dici appresso le obiezioni dei miei interlocutori
sarebbero più o meno state:
1. Parliamo di C e non di C++ per favore.
2. Tutte belle parole ma il succo del discorso non cambia: un array non
è altro che un puntatore costante con memoria allocata staticamente.
Che ne pensi? Come posso convincerli del contrario?
EMG

 di memoria.
E se quel qualcuno ti dice "dettagli sintattici: la realtà è che un
array è semanticamente indistinguibile da un puntatore costante al suo
primo elemento" cosa gli rispondi?
EMG


Che se fanno un
const_cast<T*> ptr = &array[5];
 la loro obiezione va a farsi friggere...
Paolo
----------------------------------------------------------
  Paolo Marotta
  Computer Science, University of Pisa
  home:   
http://www.cli.di.unipi.it/~marotta
  e-mail: 
mar...@cli.di.unipi.it
 
----------------------------------------------------------

 primo elemento" cosa gli rispondi?
Gli rispondo, ad esempio:
#include <iostream>
int main()
{
    int array[7];
    int* const puntatore = &array[0];
    std::cout << "Array: " << sizeof(array) << '\n'
        << "Puntatore: " << sizeof(puntatore) << '\n'
        << "\"Indistinguibile\", eh?-)\n";
    return 0;
}
Piu` elegante, forse, fare vedere quanto semanticamente
distinguibili siano i due tipi con altri costrutti (overload,
template, ecc), ma questo si traduce facilmente anche a
C (e chi fa affermazioni del genere mostra di non avere
buona conoscenza neppure di C, figurati di C++).
Alex

 Che ne pensi? Come posso convincerli del contrario?
"Non c'e` peggior sordo di chi non vuol sentire"; se, come me,
ti diverti a mostrare quanto imbecilli sono gli imbecilli, divertiti
pure ad accumulare controesempi che dimostrano la falsita`
dei loro asserti, ma non ti illudere di potere "convincere" qualcuno
deciso ad essere cosi` irragionevole!-)
Comunque, se la discussione dev'essere limitata al C, ti
consiglio di spostarla su it.comp.lang.c.
Alex

 primo elemento" cosa gli rispondi?
Francamente mi sfugge il senso di una simile discussione. Si sconfina nella
filosofia, ma per una questione che mi sembra un po' futile. Tutte le cose che
hanno qualche somiglianza possono risultare "uguali" o "diverse" a seconda dei
criteri di confronto. Se qualcuno decide che certi aspetti che rendono array e
puntatori diversi in C e in C++ sono "dettagli sintattici", e come tali non sono
significativi, quindi li esclude dai criteri di confronto, e in ultima analisi
si
limita a prendere in considerazione cio` che e` effettivamente simile, puo`
anche concludere che si tratta della stessa cosa... ma a che scopo? per
dimostrare cosa?
Saluti
Paolo

  la loro obiezione va a farsi friggere...
Scusa, scusa: potresti chiarire questa cosa? Non ho capito niente.
Quello che hai scritto è sintatticamente corretto? E cosa volevi
intendere? Delucidami...
EMG

 buona conoscenza neppure di C
Infatti così è cominciata la discussione. Ma non sono stato creduto...
:-(
EMG

 dimostrare cosa?
Mah, fondamentalmente io ho reagito ad uno che diceva "array e puntatori
sono la stessa cosa". Siccome sono anni che leggo e dico il contrario,
mi sembrava strano accettare in silenzio una tale affermazione.
EMG

 ti diverti a mostrare quanto imbecilli sono gli imbecilli,
No, non mi diverto affatto in quanto ho sempre il timore di stare
sbagliando io. Chi è profondamente convinto di una cosa, anche se
sbagliata, può riuscire a convincere uno come me che per sua natura non
è mai sicuro al 100% delle cose.
EMG


C'e` un errore di sintassi era const_cast<T*> (ptr) = &array[5];
e questo e` un esempio funzionante:
#include <iostream>
int main(int, char*[]) {
  int array[5] = { 1,2,3,4,5 };
  const int* ptr = array;
  cout << *ptr << endl;
  const_cast<int*> (ptr) = &array[2];
  cout << *ptr << endl;
  return 0;
}
veniamo alle spiegazioni:
Praticamente eseguo un cast sul puntatore per rimuovere il const e
quindi modifico il puntatore (niente di strano tutto legale e standard),
operazione che ovviamente non puo` essere fatta sull'array.
Ergo non sono la stessa cosa (ne semanticamente e neanche sintatticamente), a riprova
anche che in C++ le "sottigliezze sintattiche" nascondono profonde differenze semantiche.
Ovviamente l'esempio sopra e` C++, ma va bene anche per il C (modificando
il cast) dove tra l'altro il type system e` assai meno robusto.


tornano ad essere indistinguibili". Che gli racconto?
Che questo di per se` e` sufficiente a dire che i due oggetti sono
cose assai diverse. E comunque cio` mostra la scarsa padronanza
dell'argomento che costoro hanno.


 anche che in C++ le "sottigliezze sintattiche" nascondono profonde differenze semantiche.
A parte la svista del const messo nel punto sbagliato (sempre che abbia
visto giusto) questo purtroppo temo che non li avrebbe convinti. Il
problema è che loro, probabilmente per il tipo di lavoro che svolgono,
vedono il linguaggio da un livello troppo basso. Praticamente vanno a
vedere il codice ASM generato e dicono "qui si vede chiaramente che
l'array è implementato come puntatore al suo primo elemento". In
effetti, dal punto di vista pratico, non posso dar loro torto ma un
linguaggio ad alto livello serve proprio per nascondere questi dettagli
ed offrire al programmatore una visione più astratta. E quindi ritengo
completamente sbagliato rifiutare quelle che sono le convenzioni che il
linguaggio pone per tentare di costruire un modello coerente. Ma tanto
loro non si convincono... :-(
EMG

 dell'argomento che costoro hanno.
Benissimo, proprio quello che ho detto loro. E sai qual'è stata la
risposta? "Noi conosciamo il linguaggio ma anche come questo funziona
internamente e quindi abbiamo una conoscenza migliore". Come convincerli
del contrario?
EMG

tornano ad essere indistinguibili". Che gli racconto?
Sempre nell'ipotesi che ti diverti a mostrare agli imbecilli quanto
sono imbecilli, gli fai compilare e linkare i seguenti programmi C:
::taglia ext_puntatore.c
#include <stdio.h>
extern char* const pc;
void ext_puntatore()
{
    printf("puntatore: %s\n", pc);
}
::taglia ext_array.c
#include <stdio.h>
extern char pc[];
void ext_array()
{
    printf("array: %s\n", pc);
}
::taglia aep.c
#include <stdio.h>
extern void ext_puntatore(void);
extern void ext_array(void);
char pc[] = "Pippo mangia la mela";
int main()
{
    for(;;) {
        char c;
        char restoriga[1024];
        printf("A)rray, P)untatore, E)sci: ");
        if(!scanf("%c", &c)) break;
        switch(c) {
            case 'A': case 'a': ext_array(); break;
            case 'P': case 'p': ext_puntatore(); break;
            case 'E': case 'e': exit(0); break;
        }
        if(!gets(restoriga)) break;
    }
    return 0;
}
:: fine
Se, come dicono questi emeriti imbecilli (tali perche`
insistono a propugnare una tesi ridicola e insostenibile
a disdegno dell'evidenza), array e puntatore costante
sono la stessa cosa, allora le due funzioni ext_...()
dovranno avere qui lo stesso comportamento, si`?
Ebbene, com'e` facile provare, cosi` non e`: visto che
un array, e un puntatore costante, sono invece due
cose drasticamente diverse, e qui l'oggetto "pc" e` un
array (NON un puntatore), la ext_puntatore(), invece
di emettere come ext_array() la frase voluta, sparera`
sullo schermo spazzatura, o nulla, o causera` una
terminazione anomala del programma.
Per far funzionare ext_puntatore(), basta (e occorre)
cambiare la definizione di pc a quella di puntatore:
    char * const pc = "Pippo mangia la mela";
A questo punto, naturalmente, si guastera` la
ext_array()...!
Alex

del contrario?
Personalmente non ci spererei, persone di quel "calibro" non sono capaci di
mettersi in discussione. Comunque mi piacerebbe sapere cosa direbbero in merito
al mio (nuovo) controesempio.


l'array è implementato come puntatore al suo primo elemento".
Non mi intendo di codice asm piu` di tanto, ma dal codice generato
(che tra l'altro varia da compilatore a compilatore) dovrebbero capire
che le due cose vengono trattate in modo diverso.
L'indirizzo di un  array viene trattato come una costante in senso matematico,
mentre un puntatore costante e una costante nel senso che il compilatore
ne impedisce la modifica salvo cast espliciti. Il fatto che i due meccanismi
siano implementati in modo simile non significa che siano la stessa cosa.
E comunque la discussione verte sul piano del C++, se scendiamo all'assembler
si cambiano le carte in tavola, d'altronde a livello di assembler non si
riuscirebbe a distinguere il C dal C++ della cui differenza nessuno dubita.


 sono imbecilli, gli fai compilare e linkare i seguenti programmi C:
Beh, a questo punto io, che sto facendo da avvocato del diavolo, non
riesco a trovare alcun argomento contrario. Col tuo permesso sottoporrò
tale codice all'attenzione dei miei amici di FidoNet. Vedremo se loro
riusciranno a controbattere qualcosa...
EMG

 riuscirebbe a distinguere il C dal C++ della cui differenza nessuno dubita.
Ottimo! Faccio tesoro di tutti i vostri consigli...
EMG


Esatto! La via migliore e` un esempio che dimostri che le due cose non
si comportano allo stesso modo, ne sintatticamente ne semanticamente.
Se proprio vuoi continuare la discussione (infinita) con loro, la miglior
via e` quella utilizzata da Socrate: portare l'altra parte in contraddizione.
Non cercare nuovi argomenti, limitati a dimostrare che le loro tesi sono
false (in questo modo ti ritrovi sempre un passo avanti ;-) ).



Scusate se mi intrometto nella discussione, ma non mi sembra sia una
questione di conoscenza o meno del linguaggio.
A me sembra tanto una di quelle discussioni senza capo ne' coda, dove
tutti hanno un po' ragione e tutti un po' torto.
E' come chiedersi se :
const int  a = 10;
e
int a = 10;
sono equivalenti.
Dal punto di vista del C++ hanno significati diversi, ma se andiamo a
vedere il codice assembler non ci sarà nessuna differenza.
Per cui sono sia la stessa cosa che due cose diverse, dipende solo dal
punto di vista di chi la osserva.
Ciao.

punto di vista di chi la osserva.
Il fatto e` che quando qualcuno dice una fesseria cerca un nuovo punto di vista
per trasformarla in una sacrosanta verita`.


punto di vista di chi la osserva.
Le due cose non saranno mai la stessa, indipendentemente
dal punto di vista.
Diciamo che hai scelto male l'esempio.  Esistono casi in cui
due costrutti diversi del linguaggio sono definiti con la stessa
semantica, ad esempio:
    class A {}; class B: public A {};
    A* atob1(B* b) { return b; }
    A* atob2(B* b) { return static_cast<A*>(b); }
Qui, atob1 e atob2 DEVONO fare la stessa identica cosa, a
norma dello standard, e quindi e` presumibile che lo faranno,
piu` o meno in tutti i compilatori, con lo stesso codice assembler.
In questi casi, tuttavia, l'equivalenza e` *esplicitamente* tale.
Nello standard, la semantica di static_cast<>, applicato nei casi
in cui si avrebbe comunque una conversione automatica, e`
infatti *esplicitamente* definita come equivalente alla conversione
stessa.  Questo non vuol dire che static_cast "sia la stessa cosa"
di nulla, naturalmente, poiche` esistono tanti altri casi in cui la
conversione automatica non ci sarebbe mentre un esplicito
static_cast<> la forza comunque.  Ma, nei casi di conversione
automatica ed implicita, si puo` qui asserire che static_cast e`
ridondante.  Anche cosi`, non vuol dire che sia inutile discuterne,
perche` scriverlo esplicitamente o meno fa una notevole
differenza di stile, leggibilita`, manutenibilita`, elementi opinabili
(a differenza degli aspetti sintattici e semantici, non opinabili
in quanto rigorosamente stabiliti dallo standard) ma pur sempre
importanti; ognuno alla fine la pensera` come vuole, ma una
discussione dei pro e dei contro puo` aiutare ciascuno a formarsi
le proprie opinioni su di una base migliore, il che e` utile.
Alex

 vedere il codice assembler non ci sarà nessuna differenza.
Non sono d'accordo. Non è affatto detto che una const int e una int
siano implementate allo stesso modo. Per dire, può darsi che la const
sia memorizzata in un tipo di memoria diverso (protetta contro la
scrittura) e gestita in modo diverso. Secondo me fare assunzioni di
basso livello di qualunque tipo su come lavori il compilatore è il modo
migliore di preparare la strada ai guai. Quando si programma con un
linguaggio ad alto livello si dovrebbero seguire le _sue_ regole e non
quelle di un livello di astrazione inferiore.
EMG

 Ad ogni modo, come gia` fatto notare, con persone simili non vale la pena perdere tempo...
Purtroppo alcune di queste persone, conoscendole, so che sono molto
valide e quindi non posso semplicemente liquidarle dicendo loro di
essere ignoranti in materia perché, appunto, non lo sono. Tutt'altro.
EMG

valide e quindi non posso semplicemente liquidarle dicendo loro di
Se sono valide una presa di posizione sbagliata e sostenuta di fronte a
prove schiaccianti non mi sembra deponi a loro favore.
Comunque mi riferivo alla discussione non tanto all'ignorare quelle
persone. A parte il fatto che se dovessimo ignorare chiunque non la
pensi come noi (anche in minima parte) resteremmo soli, questo non vuol
dire che sul resto non abbiano una qualche (anche grande) valenza.
Comunque penso che la validita` di un individuo si misuri anche dalla
sua capacita` di mettersi in discussione IMO!
Ma questo e` un altro discorso.
Saluti,



Ok, visto che specifichi un compilatore tipico suppongo che compilatori
diversi possano fare cose differenti, sbaglio ?
Dato che abbiamo approfondito con un compilatore tipico, mi sono preso
la briga di scrivere quattro righe di codice, per curiosità :
1) const int a = 10;
2) int b = 10;
3) *((int *)&a) = 11;
4) b = 11;
5) <stampa  a >
6) <stampa  *((int *)&a) >
7) <stampa b>
e di compilarle su vari compilatori. Ecco cosa ho osservato:
a) VC++ 5.0: non dà memoria per la costante 'a'. Non genera errori o
warning in compilazione ma da errore in esecuzione all'istruzione 3.
(domanda: se per 'a' non è allocata memoria, perchè non mi da' neanche
un warning quando cerco di ottenerne l'indirizzo di memoria ? )
b) BCB 1.0: dà memoria per la costante 'a', tuttavia ottimizza
l'istruzione 5 stampando direttamente il valore 10, mentre
nell'istruzione 6 stampa il valore 11 (va a vedere all'indirizzo
allocato, appunto)
c) Power ++ 2.0 (usa il compilatore Watcom 10.6). Si comporta come il
BCB.