2016-02-13 11 views
9

Se si definisce una macro come #define LOGIC_ONE 1 e si desidera utilizzare LOGIC_ONE in un'istruzione case, quale tipo è considerato LOGIC_ONE?Che tipo è considerata una macro?

È riconosciuto come int poiché lo sto definendo per il valore 1?

+1

Per vedere ciò che il preprocessore fa, passa '-E' al compilatore. (msvc, gcc, clang all accetta '-E') – Ben

risposta

19

I macro C++ sono semplici sostituzioni di testo.

All'avvio del compilatore, il tuo LOGIC_ONE è già stato sostituito dal precompilatore da 1. È proprio come se avessi scritto 1 subito. (Il che, in questo caso, è un int letterale ...)

Modifica per includere la discussione nei commenti:
Se voi (o qualcun altro con accesso al codice) cambia il vostro #define LOGIC_ONE 1-#define LOGIC_ONE "1" cambierebbe il suo comportamento nel programma e diventa un valore letterale const char[].

Edit:
Dato questo post ha ottenuto più attenzione di quanto mi aspettassi, ho pensato aggiungere i riferimenti al C++ 14 Standard per quelli curiosi:

2.2 Fasi della traduzione [lex.phases]
(...)
4. Le direttive di preelaborazione vengono eseguite, le chiamate di macro vengono espanse e le espressioni di operatore unarioPragma vengono eseguite. (...) Tutte le direttive di pre-elaborazione sono quindi cancellate.
(...)
7. I caratteri di spazio bianco che separano i token non sono più significativi. Ogni token di preelaborazione viene convertito in un token. (2.6). I token risultanti sono analizzati sinteticamente e semanticamente e tradotti come un'unità di traduzione.

Come indicato, le macro vengono sostituite nella fase 4 e non sono più presenti in seguito. L'analisi "sintattica e semantica" ha luogo nella fase 7, dove il codice viene compilato ("tradotto").

letterali interi sono specificati in

2.13.2 letterali interi [lex.icon]
(...)
Un numero intero letterale è una sequenza di cifre che non ha periodo o esponente parte, con facoltativo che separa le virgolette singole che vengono ignorate nel determinare il suo valore. Un valore letterale intero può avere un prefisso che ne specifica la base e un suffisso che ne specifica il tipo.
(...)

Tabella 5 - Tipi di letterali interi

Suffix | Decimal literal  | Binary, octal, or hexadecimal literal 
----------------------------------------------------------------------------- 
none   | int     | int 
      | long int    | unsigned int 
      | long long int   | long int 
      |      | unsigned long int 
      |      | long long int 
      |      | unsigned long long int 
----------------------------------------------------------------------------- 
u or U  | unsigned int   | unsigned int 
      | unsigned long int  | unsigned long int 
      | unsigned long long int | unsigned long long int 
----------------------------------------------------------------------------- 
l or L  | long int    | long int 
      | long long int   | unsigned long int 
      |      | long long int 
      |      | unsigned long long int 
----------------------------------------------------------------------------- 
Both u or U | unsigned long int  | unsigned long int 
and l or L | unsigned long long int | unsigned long long int 
----------------------------------------------------------------------------- 
ll or LL  | long long int   | long long int 
             | unsigned long long int 
----------------------------------------------------------------------------- 
Both u or U |unsigned long long int | unsigned long long int 
and ll or LL |      | 

Le stringhe sono specificate nella

2.13.5 stringa letterali [lex.string]
(...)
1 Una stringa letterale è una sequenza di caratteri (come definita in 2.13.3) circondata da virgolette, facoltativamente preceduta da R, u8, u8R, u, uR, U, UR, L, rLR, come in " ... ", R" (...) ", u8" ... ", u8R" ** (...) ** ", u" ... ", uR" * ~ (...) * ~ ", U" ... ", UR" zzz (...) zzz ", L" ... "o LR" (...) ", rispettivamente.
(...)
6 Dopo la fase di conversione 6, un letterale di stringa che non inizia con un prefisso di codifica è un normale stringa letterale e viene inizializzato con i caratteri specificati.
7 Una stringa letterale che inizia con u8, come u8 "asdf", è una stringa letterale UTF-8.
8 I valori letterali stringa normali e i valori letterali stringa UTF-8 vengono anche chiamati valori letterali stringa ristretti. Un letterale stringa stretto ha tipo "matrice di n const char", dove n è la dimensione della stringa come definito di seguito e ha la durata di archiviazione statica (3.7).

+0

I.e. Posso trattare 'LOGIC_ONE' come se fosse un' int'? – Noobgineer

+0

@Noobgineer per il valore corrente si, ma cosa succede se qualcuno lo cambia in "" 1 "' –

+2

Puoi trattarlo in qualsiasi modo puoi trattare '1'- quindi sì, è un letterale int. – Anedar

8

LOGIC_ONE è sostituito da 1 ovunque compaia. Per quanto riguarda il compilatore, LOGIC_ONE non esiste, vede solo 1. Quindi la tua domanda è 'è 1 e int?'. La risposta è -> dipende da dove si digita il numero 1

+0

Ok. Non sapevo se il compilatore cercasse '1' o' LOGIC_ONE'. Grazie per il chiarimento! – Noobgineer

6

Una macro è una sostituzione di testo. 1 è di tipo constexpr int.

11

Le definizioni del preprocessore non hanno alcun tipo - sono fondamentalmente solo "incollate" nel codice in cui appaiono. Se ad esempio lo usi nella dichiarazione;

int foo = LOGIC_ONE; 

Quindi verrà interpretato come numero intero. (Il compilatore, che viene eseguito dopo il preprocessore, vede solo quel codice come int foo = 1;). Puoi anche usarlo in una grottosa istruzione come;

int foo##LOGIC_ONE; 

Poi ti verrà creando una variabile foo1. Che schiffo!

Prendere un esempio alternativo di definizione macro;

#define LOGIC_ONE hello 
int LOGIC_ONE = 5; 
printf("%d\n", hello); 

Questo è perfettamente valido, e dichiara un int chiamato ciao, ma dimostra che non esiste un "tipo" per la definisce - hello era semplicemente sostituito ovunque LOGIC_ONE stato rilevato nel codice.

Evitare l'uso di macro del preprocessore a meno che non sia assolutamente necessario. Gli standard di codifica professionale spesso proibiscono o limitano severamente l'uso del preprocessore. Di solito ci sono sempre modi migliori per fare cose rispetto all'utilizzo di macro. Ad esempio, considera queste alternative;

static const int LOGIC_ONE = 1; 
enum { LOGIC_ONE = 1 }; 

Il preprocessore è un modo rapido per uno studente di entrare in un vero e proprio caos in C.

+1

Grazie per la spiegazione dettagliata. Le macro sono state fornite come parte di un'API che devo usare e non sono autorizzato a modificare, ma seguirò il tuo consiglio per evitare le macro del preprocessore per i progetti futuri! – Noobgineer

+0

Ho pensato che l'inserimento di token funzionasse solo con argomenti macro e non fosse applicato alle macro in generale? – supercat

+0

Il consiglio contro qualsiasi cosa, ma con usi molto limitati di macro, è di 10 volte in C++ (che è contrassegnato da questa domanda). C'è quasi certamente un modo migliore per la sicurezza del tipo di ciò che è possibile ottenere con i macro. L'inclusione dei file, le protezioni incluse e la compilazione condizionale sono i rimanenti soggiorni principali di pre-elaborazione. – Persixty

Problemi correlati