Perché un compilatore non può evitare di importare un file di intestazione due volte da solo?

12

Nuovo in C ++! Quindi stavo leggendo questo: link

Header guards

Because header files can include other header files, it is possible to end up in the situation where a header file gets included multiple times.

Quindi creiamo direttive preprocessore per evitarlo. Ma non sono sicuro: perché il compilatore non può ... non importare la stessa cosa due volte?

Dato che le guardie di intestazione sono opzionali (ma a quanto pare una buona pratica), mi fa quasi pensare che ci siano degli scenari quando vuoi importare qualcosa due volte. Anche se non riesco a pensare a nessuno di questi scenari. Qualche idea?

    
posta Omega 26.03.2013 - 19:36
fonte

3 risposte

27

Possono, come mostrano le nuove lingue.

Ma una decisione progettuale è stata presa tutti quegli anni fa (quando il compilatore C era più fasi indipendenti) e ora per mantenere la compatibilità il pre-processore deve agire in un certo modo per assicurarsi che il vecchio codice compili come previsto.

Poiché C ++ eredita il modo in cui elabora i file di intestazione da C, mantiene le stesse tecniche. Stiamo supportando una vecchia decisione di progettazione. Ma cambiare il modo in cui funziona è troppo rischioso e molti codici potrebbero potenzialmente rompersi. Quindi ora dobbiamo insegnare ai nuovi utenti del linguaggio come usare le guardie.

Ci sono un paio di trucchi con i file di intestazione se lo includi volutamente più volte (questo in realtà fornisce una funzionalità utile). Anche se abbiamo ridisegnato il paradigma da zero, potremmo rendere questo il modo non predefinito di includere i file.

    
risposta data 26.03.2013 - 19:44
fonte
7

Non sarebbe altrimenti espressivo, dato che hanno scelto di mantenere la compatibilità con C e quindi di continuare con un preprocessore piuttosto che un sistema di imballaggio tradizionale.

Una cosa che mi viene in mente è che avevo un progetto che era un'API. Ho avuto due file di intestazione x86lib.h e x86lib_internal.h . Poiché interno era enorme, ho separato i bit "pubblici" in x86lib.h in modo che gli utenti non dovessero dedicare più tempo alla compilazione.

Questo ha introdotto un problema divertente con le dipendenze, anche se così ho finito per avere un flusso che andava così in x86lib_internal

  1. Imposta il preprocessore INTERNO definisci
  2. Include x86lib.h (che era intelligente per agire in un certo modo quando era definito l'interno)
  3. Fai alcune cose e presenta alcune cose usate in x86lib.h
  4. Imposta AFTER il preprocessore definisce
  5. Includi di nuovo x86lib.h (questa volta ignorerebbe tutto tranne una parte AFTER separata che dipendeva da elementi di x86lib_internal

Non direi che era il modo migliore per farlo, ma ha ottenuto ciò che volevo.

    
risposta data 26.03.2013 - 19:51
fonte
0

Una difficoltà con l'esclusione automatica dell'intestazione dei duplicati è che lo standard C è relativamente silenzioso sul tema di ciò che significa che i nomi dei file includono. Ad esempio, supponiamo che il file principale da compilare contenga le direttive #include "f1.h" e #include "f2.h" , e che i file trovati per tali direttive contengano entrambi #include "f3.h" . Se f1.h e f2.h sono in directory diverse, ma sono stati trovati cercando i percorsi di inclusione, non sarebbe chiaro che le direttive #include all'interno di quei file fossero intese per caricare lo stesso file f3.h , o diversi.

Le cose peggiorano ulteriormente se si aggiunge la possibilità di includere i file, compresi i percorsi relativi. In alcuni casi in cui i file di intestazione utilizzano percorsi relativi per le direttive di inclusione nidificata e dove si desidera evitare di apportare modifiche ai file di intestazione forniti, potrebbe essere necessario duplicare un file di intestazione in più punti all'interno della struttura di directory di un progetto. Anche se esistono più copie fisiche di quel file di intestazione, dovrebbero essere considerate semanticamente come se fossero un singolo file.

Se la direttiva #pragma once ha permesso a un identificatore di seguire once , con la semantica che il compilatore dovrebbe saltare il file se l'identificatore corrisponde a una direttiva #pragma once incontrata in precedenza, la semantica non sarebbe ambigua; un compilatore che potrebbe dire che una direttiva #include avrebbe caricato lo stesso file con #pragma once -tagged come una precedente, potrebbe risparmiare un po 'di tempo saltando il file senza aprirlo di nuovo, ma tale rilevamento non sarebbe semanticamente importante dal il file sarebbe saltato indipendentemente dal fatto che il nome del file fosse riconosciuto o meno come una corrispondenza. Tuttavia, non sono a conoscenza di alcun compilatore che lavori in quel modo. Avere un compilatore osserva se un file corrisponde al modello #ifndef someIdentifier / #define someIdentifier / #endif [for that ifndef] / nothing following e il trattamento di una cosa equivalente al precedente #pragma once someIdentifier se someIdentifier rimane definito, è essenzialmente buono.

    
risposta data 20.02.2015 - 19:49
fonte

Leggi altre domande sui tag