Include l'implementazione di GCC delle parentesi angolari. Perché deve essere come descritto di seguito?


11

Questo documento nella sua sezione 2.6 Include comprende ha il seguente paragrafo:

Se la linea si espande in uno stream token che inizia con un token <e include un token>, i token tra <e il primo> vengono combinati per formare il nome file da includere. Qualsiasi spazio bianco tra i token viene ridotto a un singolo spazio; quindi viene mantenuto qualsiasi spazio dopo <iniziale, ma viene ignorato uno spazio finale prima della chiusura> . CPP cerca il file in base alle regole incluse nella parentesi angolare.

So che questa definizione è definita, ma perché deve essere così per GCC? Mi riferisco specificamente alla frase evidenziata sopra.

MODIFICARE

Ho appena notato che il terzo paragrafo prima di quello sopra citato dice quanto segue:

Devi fare attenzione quando definisci la macro. #definesalva i token, non il testo. Il preprocessore non ha modo di sapere che la macro verrà utilizzata come argomento di #include, quindi genera token ordinari, non un nome di intestazione. È improbabile che ciò causi problemi se si utilizzano inclusioni a virgoletta doppia, abbastanza vicine alle costanti di stringa. Se si utilizzano parentesi angolari, tuttavia, si potrebbero avere problemi .

Qualcuno sa che tipo di problema viene segnalato qui?


6
La migliore ipotesi è che gli sviluppatori di GCC pensino che avere spazi alla fine di un nome file sia un abominio.
user3386109

1
I nomi di file con spazi iniziali e / o finali sono molto difficili da svegliare, specialmente su Windows.
Remy Lebeau,

1
Solo perché è stato definito in questo modo, non significa necessariamente che debba essere definito in questo modo. Non è obbligatorio per lo standard.
eerorika,

Visual Studio rimuove lo spazio iniziale e finale, quindi si comporta in modo diverso. HP aCC si comporta come gcc (forse per motivi di compatibilità).
Slimak,

A volte la documentazione descrive semplicemente cosa succede al codice invece del contrario, specialmente nei casi che non contano (puoi usare qualsiasi spazio ovunque se usi virgolette doppie).
Rustyx,

Risposte:


9

Immagino che l'implementatore abbia scelto il modo più semplice quando ha implementato questa funzionalità, senza pensarci troppo.

Sembra che l'implementazione iniziale sia arrivata nel 2000-07-03 (due decenni fa!). La parte pertinente appare come ( fonte ):

  for (;;)
    {
      t = cpp_get_token (pfile);
      if (t->type == CPP_GREATER || t->type == CPP_EOF)
        break;

      CPP_RESERVE (pfile, TOKEN_LEN (t));
      if (t->flags & PREV_WHITE)
        CPP_PUTC_Q (pfile, ' ');
      pfile->limit = spell_token (pfile, t, pfile->limit);
    }

In particolare, scoppia quando vede il CPP_GREATERtoken (cioè >), prima di riservare memoria per il token. Questo ha senso, poiché non è necessario allocare memoria quando il token non verrà scritto nel buffer.

Quindi, solo dopo che la memoria è stata prenotata, il preprocessore controlla se il token ha uno spazio bianco precedente ( t->flags & PREV_WHITE) e quando lo fa, scrive un carattere di spazio bianco nel buffer.

Di conseguenza, in < foo / bar >, solo gli spazi bianchi prima foo(cioè dopo l'iniziale <) /, e barvengono mantenuti.


Ottima risposta. Questa è la prima volta che ho l'opportunità di vedere un pezzo di codice in GCC. Grazie per questo.
Ayrosa,

Ma non è il caso che la condizione if (t->flags & PREV_WHITE) CPP_PUTC_Q (pfile, ' ');contraddica ciò che viene detto nel documento: "Qualsiasi spazio bianco tra i token è ridotto a un singolo spazio; ..."?
Ayrosa,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.