Per rispondere alle tue domande, pensa a quali macro vengono utilizzate principalmente (Attenzione: codice compilato dal cervello).
- Le macro utilizzate per definire le costanti simboliche
#define X 100
Questo può essere facilmente sostituito con: const int X = 100;
- Le macro utilizzate per definire (essenzialmente) funzioni agnostiche di tipo inline
#define max(X,Y) (X>Y?X:Y)
In qualsiasi linguaggio che supporti il sovraccarico delle funzioni, questo può essere emulato in un modo molto più sicuro di tipo avendo funzioni sovraccaricate del tipo corretto o, in un linguaggio che supporta generici, da una funzione generica. La macro tenterà felicemente di confrontare qualsiasi cosa, inclusi puntatori o stringhe, che potrebbero essere compilati, ma quasi sicuramente non è quello che volevi. D'altra parte, se le macro sono state rese sicure per i tipi, non offrono vantaggi o praticità rispetto alle funzioni sovraccariche.
- Macro utilizzate per specificare collegamenti a elementi di uso frequente.
#define p printf
Questo è facilmente sostituito da una funzione p()
che fa la stessa cosa. Questo è abbastanza coinvolto in C (che richiede di usare ilva_arg()
famiglia di funzioni) ma in molti altri linguaggi che supportano un numero variabile di argomenti di funzioni, è molto più semplice.
Supportare queste funzionalità all'interno di una lingua piuttosto che in un linguaggio macro speciale è più semplice, meno soggetto a errori e molto meno confuso per gli altri che leggono il codice. In realtà, non riesco a pensare a un singolo caso d'uso per le macro che non può essere facilmente duplicato in un altro modo. L' unico posto in cui le macro sono veramente utili è quando sono legate a costrutti di compilazione condizionali come #if
(ecc.).
Su questo punto, non discuterò con te, poiché credo che le soluzioni non preprocessore alla compilazione condizionale in linguaggi popolari siano estremamente ingombranti (come l'iniezione di bytecode in Java). Ma linguaggi come D hanno messo a punto soluzioni che non richiedono un preprocessore e non sono più ingombranti rispetto all'utilizzo dei condizionali del preprocessore, pur essendo molto meno soggetti a errori.