Newsgroup: it.comp.lang.c++
Titolo: "const" vs "#define"

So che una "#define" serve a definire una macro e che puo' essere usata anche
per definire variabili globali con valore fisso non modificabile. Ricordo
anche che definendo una variabile con una "#define", laddove faccio uso della
variabile dichiarata, l'eseguibile sara' molto piu' rapido di una semplice
dichiarazione di una variabile con "const". 
Restando d'accordo sul fatto che "const" non mi permette di eseguire macro e
che e', diciamo, piu' lento in fase di runtime, mi stavo chiedendo
esattamente quale fosse la ragione della differenza in prestazioni e cosa
accade in dettaglio al momento dell'esecuzione.
-- 
Kristian

"Kristian" <kris...@panda.casa> wrote


Allora non sono d'accordo che const e' piu' lento, se hai un buon
compilatore sapra' come ottimizzare un const nella maggior parte dei casi.
#define e' una cosa profondamente diversa. Il complilatore, quando riceve il
codice da compilare non vede nemmeno piu' la #define in quanto viene
processata dal pre-processore. In pratica se hai:
#define NUM 5
int val = NUM;
NUM;
il preprocessore prendera il codice e sostituira' ogni occorrenza di NUM con
il valore 5:
int val = 5;
5;
ora il compilatore compilera' il codice, ma come vedi NUM non esiste piu' e
nemmeno la #define.
Const invece viene data in pasto al compilatore. In teoria e' piu' lenta
perche' invece di essere un valore (5) e' una variabile che contiene un
valore e quindi devi accedere alla memoria e leggere il valore. In pratica i
compilatori sono abbastanza intelligenti da ottimizzare il codice e in un
codice del genere;
{
    const int val = 5;
    cout << val << endl;
}
nessun compilatore intelligente si sognerebbe di allocare un var sullo
stack, metterci il valore 5, poi leggere il la locazione di memoria,
prendere il valore e visualizzarlo.... Un compilatore capisce che il codice
si puo' ottimizzare e produrre lo stesso codice che sarebbe stato prodotto
se avessimo scritto:
{
     cout << 5 << endl;
}
Quindi l'ottimizzatore fa un buon lavoro e tu puoi tranquillamente usare
const che e' molto meglio e' piu' sicuro di #define.
Il compilatore vede la keyword const (al contrario di #define), fa un
controllo sul tipo etc...
Per sapere quanto e' pericolo #define pensa alla seguente:
#define COSTO_MELA 5
#define IVA_MELA 1
#define TOTALE_MELA COSTO_MELA + IVA_MELA
#define NUMERO_MELE 25
cout << "Il costo totale di 25 mele e' di : " << TOTALE_MELA * NUMERO_MELE
<< endl;
Tu ti aspetti 6 * 25 = 150, ma invece fa 30 perche' viene sostituito cosi':
cout << "Il costo totale di 25 mele e' di : " << TOTALE_MELA * NUMERO_MELE
<< endl;
cout << "Il costo totale di 25 mele e' di : " << COSTO_MELA + IVA_MELA * 25
<< endl;
cout << "Il costo totale di 25 mele e' di : " << 5 + 1 * 25 << endl;
dove 5 + 1 * 25 fa ovviamente 30.
In pratica per avere il giusto risultato avresti dovuto scrivere:
cout << "Il costo totale di 25 mele e' di : " << (TOTALE_MELA) * NUMERO_MELE
<< endl;
che non ha molto senso a chi lo vede!
Oppure aver definito :
#define TOTALE_MELA (COSTO_MELA + IVA_MELA)
Ovviamente se usi const eviti tutti questi problemi:
const int COSTO_MELA  = 5;
const int IVA_MELA = 1;
const int TOTALE_MELA = COSTO_MELA + IVA_MELA;
const int NUMERO_MELE = 25;
cout << "Il costo totale di 25 mele e' di : " << TOTALE_MELA * NUMERO_MELE
<< endl;
e senza bisogno di alcuna parentesi (ne nella definizione di totale mela, ne
nella cout) il totale e', come ci si aspetta, 150.
Ovviamente il codice eseguibile e' altrettanto veloce, solo che
l'ottimizzazione viene fatta a livello del compilatore e non del
pre-processore.
Il pre-processore e' stupido, sostituisce solo, il compilatore e' uno dei
programmi piu' intelligenti che esistano.
In alcuni rari casi pero' e' vero, #define puo' risultare piu' veloce di
const (se il compilatore non riesce ad ottimizzare per qualche motivo).
Tuttavia non sono queste le ottimizzazioni che devi fare ne cercare. Pensa
all'algoritmo.
La define, oltre al problema descritto sopra presenta un mucchio di
problemi, specialmente con le macro:
#define Square(a) (a*a)
Ok, semplice:
int val = 5;
cout << Square(val) << endl;
e viene stampato 25, ok.
Ora prova a fare:
int val = 5;
cout << Square(++val) << endl;
ok ti aspetti che val valga 6 e quindi 36.... ma....
proviamo a sostituire:
cout << (++val*++val) << endl;
quindi il calcolo e' 6*7 ed il risultato e' "forse" 49, non solo.... ma val,
dopo tale chiamate di funzione non vale 6 come ti aspetti ma vale invece 7
!!!
Insomma, non usare le #define.
In C++ se proprio vuoi essere veloce puoi usare una funzione inline:
inline int Square(int a)
{
     return a*a;
}
cout << Square(++val) << endl;
ora si che come ti aspetti stampa 36 e dopo la chiamata di funzione val vale
6.
Ciao,
Tommy

Beh devo dire che è stato utile anche a me....
Sei stato chiarissimo 

 dichiarazione di una variabile con "const".
Il fatto è che la const è una normalissima variabile che alloca memoria, 
anche per tutta l'esecuzione del programma, dipende come è usata.ù
Il #define invece viene sostituito in fase di compilazione del tipo:
#define A 10
#define B 11
[...]
while ((cont < A)&&(cont1>B) {
[...]
compilato equivarrà a compilare:
[...]
while ((cont < 10)&&(cont1>11) {
[...]
Quindi la quantità di ram del programma eseguito in caso di 10/20 #define 
scenderà in maniera impressionante, soprattutto se lo utilizzi per stringhe 
di caratteri, anche se in quest'ultimo caso la complessità della 
programmazione forse non è giustificata al risparmio di ram 
nell'esecuzione...
Inoltre puoi usare #undef A per eliminare la definizione di A. (Anche questo 
è sempre in fare si compilazione).
Ti ricordo che puoi usare anche #if per tagliare intere parti di codice in 
fase di compilazione in modo da sfoltire il codice, ad esempio;
#define CODICE Y
#if CODICE==Y
cout<<"Ciao Mondo";
#elif CODICE==N
[...]
#else
[...]
#endif
Ti ricordo però che #if viene valutato in fase di compilazione quindi in 
questo caso il .exe compilato equivarrà ad un sorgente del tipo:
cout<<"Ciao Mondo";
E basta.
Spero di esserti stato utile.
Ciao
-- 
Axel
Mods of Cropcirclecrew
Sezione Programmazione Domande/Risposte
http://www.cropcirclecrew.org/public/cccforum/index.php
 

 Sei stato chiarissimo 
	Si si... non c'e' che dire! Entrambi... Axel e Tommy. Grazie a tutti e
	due. Spero di poter ricambiare al piu' presto!
	Buona domenica a tutti!
-- 
Kristian

 soprattutto se lo utilizzi per stringhe di caratteri,
Se fai:
  #define PROVA "prova"
  void print(char const *);
  ...
  print(PROVA);
ovviamente il compilatore deve tenere in memoria da qualche parte un
array di caratteri con dentro "prova", come in
  print("prova");
e 
  char const * p = "prova";
  print(p);
Se poi fai:
  print(PROVA);
  print(PROVA);
  print(PROVA);
un compilatore poco furbo potrebbe generare 3 array uguali, occupando
il triplo di memoria.
        Mauro

 "la quantita' di ram scendera' in maniera impressionante"
20 variabili intere sono 80 bytes. Il mio computer ha 1GB di ram, quindi un
miliardo di bytes. Quindi l'aggettivo "impressionante" mi pare moooolto
esagerato anche nel caso in cui tale risparmio di memoria efettivamente
avvenga, cosa che, come documentata sopra, non e' per nulla garantito grazie
all'intelligenza dell'optimiser.
Tommy

 accade in dettaglio al momento dell'esecuzione.
Hai verificato quello che dici, perché a me risulta che non sia cosě, almeno
con i compilatori piů noti in circolazione.
Tra l'altro proprio al fine di migliorare il codice in generale si consiglia
di usare const il piů possibile: il codice diviene piů robusto e le
informazioni aggiuntive sul tipo promettono ottimizzazioni di codice
migliori da parte dei compilatori, mai comunque peggiori.
Forse hai provato codice senza aver attivato gli switch che abilitano
l'ottimizzazione del codice, in questo caso puň essere perché vengono create
informazioni per il debugging.
ciao.

> news:slrncmgbit....@panda.dufamily...
[extreme cutting]
Bho a me avevano insegnato cosě (male) ma il bello della vita č che c'č 
sempre da imparare :-D
Tnx
