2013-08-27 17 views
19

Ho cercato attraverso code golf ed è venuta un'idea per provare questo codice:È possibile definire un'altra direttiva preprocessore?

#define D #define dopo l'aggiunta di questa linea, tutto ha funzionato bene, ma ho ampliato in questo:

#define D #define 
D VALUE 

E qui ho ottenuto 5 errore di compilazione. Se cambio D in #define, tutto va bene, qualcuno può spiegare, perché questo codice è illegale?

NOTA: Ho usato il compilatore VS2008.

EDIT: Dopo alcune risposte che vedo che avevo bisogno di dare compilation lista degli errori:

  1. errore C2121: '#': carattere non valido: forse il risultato di una macro espansione
  2. errore C2146 : errore di sintassi: mancante ';' prima dell'identificatore "VALUE"
  3. errore C4430: identificatore di tipo mancante - int assunto. Nota: C++ non supporta default-int
  4. errore C2144: errore di sintassi: 'void' deve essere preceduto da ';'
  5. errore C4430: identificatore di tipo mancante - int assunto. Nota: C++ non supporta

primo errore default-int dimostra che non è solo Ddefine ma include anche #.

+0

Poiché potrebbe dipendere dall'implementazione, si prega di indicare quale compilatore si sta utilizzando. –

+4

"perché questo codice è illegale?" - Perché non è possibile ridefinire le direttive del preprocessore. –

+0

@ H2CO3 Sono stato in grado di ridefinirlo, perché la prima volta ha funzionato, tuttavia dopo l'uso di quella definizione ho ottenuto errore di compilazione. – ST3

risposta

10

Questo codice è illegale perché la specifica della lingua dice che è illegale. In base alle specifiche del preprocessore C e C++, qualsiasi codice creato usando il preprocessore non verrà mai interpretato come un'altra direttiva preprocessore. In breve, non è possibile creare direttive del preprocessore utilizzando il preprocessore. Periodo.

(Inoltre, non è possibile costruire i commenti tramite preprocessore.)

11

Sembra che il preprocessore stia effettuando la sostituzione desiderata, ma probabilmente non si otterrà il comportamento desiderato: il preprocessore normalmente è solo un'operazione a passaggio singolo. Esempio (con clang, ma si dovrebbe essere in grado di riprodurre utilizzando i flag VS2008 appropriate):

$ cat example.c 
#define D #define 
D VALUE 
$ cc -P -E example.c 

#define VALUE 

Questo #define VALUE sta dritto al compilatore, che non sa cosa fare con esso - è un direttiva preprocessore, dopo tutto. L'errore di Clang, per riferimento, è simile al tuo:

$ cc -c example.c 
example.c:2:1: error: expected identifier or '(' 
D VALUE 
^ 
example.c:1:11: note: expanded from macro 'D' 
#define D #define 
     ^
1 error generated. 
+15

Se il preprocessore è un'operazione a passaggio singolo o non è irrilevante. Il preprocessore non dovrebbe eseguire più di una scansione del file per rielaborare le singole righe; potrebbe semplicemente elaborare ogni riga tutte le volte che è necessario. Di fatto, lo fa: la sostituzione delle macro viene eseguita ripetutamente. Il motivo per cui le direttive del preprocessore non vengono elaborate dopo la sostituzione delle macro è perché lo standard della lingua dice di non farlo. –

+0

Sì, d'accordo. Non conoscevo le regole ufficiali. –

6

che non funzionerà, perché la pre-elaborazione viene eseguita in un unico passaggio. Ad esempio, si consideri il codice seguente:

#define MYDEFINEWEIRD #define 

MYDEFINEWEIRD N 6 

int main() { 

    return 0; 
} 

Dopo la pre-elaborazione, il codice appare come:

#define N 6 
int main() { 

    return 0; 
} 

e "# define" non è una sintassi valida su C o C++. Inoltre, poiché la direttiva del preprocessore risultante non verrà elaborata, non risolverà i successivi riferimenti alla macro "N" nel codice.

Solo per divertimento, è possibile chiamare il preprocessore due volte dalla riga di comando utilizzando g ++/gcc. Considera il prossimo codice (definisci.cpp):

#include <iostream> 

#define MYDEFINEWEIRD #define 
MYDEFINEWEIRD N 6 

using namespace std; 

int main() { 
    cout << N << endl; 
    return 0; 
} 

Poi si può fare:

$ g++ -E define.cpp | g++ -o define -x c++ - && ./define 

e la volontà di uscita:

6 
+2

"la preelaborazione viene eseguita in un singolo passaggio" - no, in realtà non lo è - e questo è ** non ** il motivo dell'errore. –

+2

@ H2CO3, penso che il risultato di questa risposta sia corretto. –

+0

@EricPostpischil Beh, vero, si dice che è un'operazione a passaggio singolo. Ma non lo è, vero? '#define FOO BAR', quindi' #define BAR 0', quindi 'return FOO;' espanso a 'return 0;' per me. –

31

C 2011 (N1570) 6.10.3.4 3: “La risultante completamente macro-sostituito la sequenza di token di preelaborazione non viene elaborata come una direttiva di pre-elaborazione anche se assomiglia a una, ... "

C++ 2010 (N309 2) 16.3.4 [cpp.rescan] 3 ha esattamente lo stesso testo.

+2

Questa è la risposta giusta. Lo standard di linguaggio C specifica l'ordine esatto delle operazioni su come viene tradotto il codice sorgente del programma. –

+1

Questo testo "anche se assomiglia ad uno" risale allo standard ANSI C del 1989 (e molto probabilmente bozze prima). – Kaz

+0

N3092 non è uno standard ... anche se il testo è indubbiamente lo stesso in C++ 98, C++ 11 e in ogni bozza standard C++ che sia mai stata o sarà mai. – Potatoswatter

1

righe di codice nel pre-processori occhi sono o istruzioni per il preprocessore (e quindi non hanno alcun sostituzioni fatto su di loro) o il testo normale dichiarazioni (E hanno fatto sostituzioni). Non puoi averne uno entrambi, quindi una volta sostituita la 'D', verrà visualizzato solo se ci sono altre macro da sostituire. Dato che non ce ne sono, lascia "#define" nel codice C++ così com'è e quindi il compilatore C++ effettuerà un errore quando lo vedrà (poiché '#define' non è un codice C++ valido).

Così mostrare il mio punto di più, questo è il codice non valido per il pre-processore:

#define D define 
#D value 

Poiché il pre-processore non fare alcuna sostituzione macro sulle dichiarazioni pre-processore, e "#D" non è un comando pre-processore riconosciuto. E questo:

#define D #define 
D value 

I risultati in questo codice C++:

#define value 

nullo a causa del pre-processore è già stato fatto in esecuzione.

1

Guardando la grammatica in 16 [CPP] paragrafo 1, un sostitutiva lista consiste di pp-gettoni che possono includere la produzione # no-direttiva che è descritto nel paragrafo 2 dello stesso paragrafo come

Una non direttiva non deve iniziare con nessuno dei nomi di direttive che compaiono nell'elenco.

cioè qualcosa della forma

#define NAME # define 

sembra essere illegale! Si noti inoltre che lo # in questo contesto non è non trasforma la parola successiva in una stringa: il quoting che segue uno # shen solo lo # viene immediatamente seguito da un nome di parametro macro in una macro di stile di funzione.

+0

Il simbolo grammaticale 'non direttivo' nella frase" Una non direttiva non inizia ... "si riferisce a una riga' # non-direttiva'. Pertanto, si tratta semplicemente di distinguere le righe che assomigliano a '# some-directive' da righe che assomigliano a' # non-directive'. Ciò non rende '#define NOME # define' come una sequenza di token del preprocessore non valida. –

Problemi correlati