Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

[C++] Perché #define non è sempre cosa buona

Linguaggi e sistemi

Moderatori: Foto UtentePaolino, Foto Utentefairyvilje

4
voti

[1] [C++] Perché #define non è sempre cosa buona

Messaggioda Foto Utentefairyvilje » 3 lug 2012, 13:29

Viste le recenti discussioni su questo punto voglio mostrare perché gli ideatori dello standard C++ hanno deciso di sostituire per molti contesti la direttiva del preprocessore #define con due nuove parole chiave const per dichiarare costanti e inline per funzioni inlinea.
Per prima cosa come funziona #define?
Si tratta di una direttiva del preprocessore quindi la sua esecuzione viene interpretata prima della compilazione effettiva. Il preprocessore nasce con lo scopo di modificare il sorgente da compilare, semplificando sostanzialmente sostituzioni ed inclusioni di files ai programmatori.
#define permette di creare una macro od una costante che prima della compilazione viene espansa nel sorgente. Perché pericolosa? Perché sfugge al controllo del C++ e gli errori che derivano dal suo utilizzo in modo non appropiato a volte sono difficili da codificare. In altri casi come mostrerò sono praticamente inscovabili.

Immaginate il seguente programma:

Codice: Seleziona tutto
#define HELLO 0x500
//...
int newValue=HELLO;


fino a qua sembra andare tutto bene no?
In effetti l'uso delle costanti è il più sicuro perché solitamente non provoca grossi problemi. Mettere i nomi in maiuscolo poi ci aiuta a capire che quella è una costante #define in casi come

Codice: Seleziona tutto
HELLO=1250;

e anche se l'errore non sarà immediato, in fondo stiamo associando un numero ad un numero, non un numero ad una costante, comunque si riesce a trovarlo.
Tuttavia alcune delle caratteristiche avanzate che il C++ supporta sulle costanti ci saranno precluse e si evidenziano limiti con costanti di tipi chiaramente non nativi.

I problemi arrivano quando si usano le macro con troppa leggerezza.
Codice: Seleziona tutto
#define OFF_POS(x,y) 0xb8000+(y*80+x)*2
//Questa macro potrebbe essere usata per ottenere la posizione di memoria si cui scrivere un carattere sullo schermo
//...
char *vgaMem=(char*)0xb8000;
vgaMem[OFF_POS(10,10)]='H';
vgaMem[OFF_POS(10,10)+1]=42;
//MI ha stampato una H colorata sullo schermo

Tutto ok? Sembrerebbe funzionare vero? Ora guardate questo...
Codice: Seleziona tutto
#define OFF_POS(x,y) 0xb8000+(y*80+x)*2
//Questa macro potrebbe essere usata per ottenere la posizione di memoria si cui scrivere un carattere sullo schermo
//...
char *vgaMem=(char*)0xb8000;
int verticalOffset=5;
vgaMem[OFF_POS(10,verticalOffset+2)]='H';
vgaMem[OFF_POS(10,verticalOffset+2)+1]=42;
//MI ha stampato una H colorata sullo schermo

La stampa sulla 8° riga? No mi dispiace... finirà da qualche parte della terza. perché in realtà il compilatore senza generare errori giustamente ha fatto questo
Codice: Seleziona tutto
vgaMem[ 0xb8000+(5+2*80+10)*2]='H';

Senza contare le precedenze degli operatori perché il preprocessore è stupido copia e basta quello che gli dite. Ora sullo schermo vedreste qualcosa che non va... ma in altri contensti questo errore sarebbe invisibile e non genererebbe errori di compilazione. Ed in esecuzione si presenterebbe solo a volte.
Chiaramente possiamo correggere il nostro #define
Codice: Seleziona tutto
#define OFF_POS(x,y) 0xb8000+((y)*80+(x))*2

Anzi fareste ancora meglio a mettere tutto fra parentesi
Codice: Seleziona tutto
#define OFF_POS(x,y) (0xb8000+((y)*80+(x))*2)

Così è abbastanza sigillato. Ora... perché correre questo rischio quando esiste una cosa chiamata funzione inline? Eccola

Codice: Seleziona tutto
inline unsigned int OFF_POS(unsigned int x, unsigned int y){return 0xb8000+(y*80+x)*2;}


Ecco il motivo di usare il C++ anziché il preprocessore, si fanno rientrare la gestione degli errori e dei bug all'interno del linguaggio stesso. Esistono caratteristiche del preprocessore utilissime come gli operatori # e ##, insostituibili è vero. Ciò che è sostituibile però sostituiamolo ;)
Avatar utente
Foto Utentefairyvilje
15,0k 4 9 12
G.Master EY
G.Master EY
 
Messaggi: 3047
Iscritto il: 24 gen 2012, 19:23

Torna a PC e informatica

Chi c’è in linea

Visitano il forum: Nessuno e 17 ospiti