2012-04-09 10 views
7

Attualmente sto studiando per un esame finale del corso CS e mi sono imbattuto in un problema minore (forse importante?) Relativo alla sintassi di C++ #ifndef.Sintassi #ifndef per includere le protezioni in C++

Ho guardato la sintassi per #infndef quando lo si utilizza come una guardia #include, e la maggior parte sul web sembrano dire:

#ifndef HEADER_H 
#define "header.h" 
... 
#endif 

Ma scivoli d'istruzione di mia classe mostrano esempi come:

#ifndef __HEADER_H__ 
#define "header.h" 
... 
#endif 

Mi stavo chiedendo cosa (se c'è) la differenza era tra i due. L'esame molto probabilmente mi chiederà di scrivere una guardia di #include, e so che la saggezza convenzionale è di andare con quello che dice il prof/tutor, ma se c'è una differenza durante la compilazione mi piacerebbe sapere.

+5

Sede [qui] (http://stackoverflow.com/questions/228783) per una discussione delle regole il tutor sta rompendo, e [qui] (http://stackoverflow.com/questions/3345159) per un esempio cosa potrebbe andare storto se li rompi. Inoltre, includi guardie vai * dentro * l'intestazione. –

+0

Così com'è, il codice nascosto non ha senso: non si può '# define' una stringa letterale. Intendevi '#include" header.h "' (il testo originale) o '#define HEADER_H' (cosa succede di solito all'interno di un preambolo di intestazione)? – Attila

risposta

17

La pratica normale è quella di non fare né, e inserire la protezione inclusa all'interno del file di intestazione, in quanto riduce la ripetizione. es .:

header.h

#ifndef HEADER_H 
#define HEADER_H 

// Rest of header file contents go here 

#endif 

Proprio quello che si utilizza come il nome della macro è giù per il vostro particolare standard di codifica. Tuttavia, ci sono varie regole sottili negli standard C e C++ che ti impediscono di usare gli identificatori che iniziano con i caratteri di sottolineatura, quindi dovresti evitare __HEADER_H__, solo per essere sicuri.

Vale anche la pena ricordare che è necessario scegliere qualcosa che è improbabile che possa scontrarsi con qualcos'altro nella base di codice. Ad esempio, se ti capita di avere una variabile denominata HEADER_H altrove (improbabile, mi rendo conto), ti ritroverai con alcuni errori esasperanti.


1. Vedere ad es. sezione 7.1.3 della norma C99.

+1

... e se non è un file di intestazione dell'implementazione, dovrebbe evitare identificativi contenenti un trattino basso seguito da un altro trattino basso o una lettera maiuscola. –

+0

@JerryCoffin: "contenente" o "che inizia con"? –

+0

Per C, a partire. Per C++, contenente un trattino basso raddoppiato è anche verboten (ma la sottolineatura seguita da cap è consentita purché non sia all'inizio). –

1

Non c'è differenza se non si utilizza il carattere di sottolineatura nei nomi di variabili in qualsiasi altro punto, è solo una convenzione di denominazione.

Hai solo bisogno di mettere qualcosa di unico.

+4

Non vero. I nomi che iniziano con due underscore sono riservati per l'implementazione (almeno in C99). –

+1

+1: In realtà risponde alla domanda dell'OP invece di affermare il "solito" modo di fare le cose. –

+4

Non è solo una convenzione. L'uso di un identificatore che inizia con un '__' rende il comportamento del codice non definito. L'implementazione (o il compilatore o la libreria standard) è libera di usare il nome '__HEADER_H__' per i propri scopi; se lo fa, il tuo uso personale di quell'identificatore potrebbe significare letteralmente * qualsiasi cosa *. –

5

I nomi che iniziano con un trattino di sottolineatura doppio sono riservati per l'implementazione, quindi sconsiglio di utilizzare __SOMETHING nelle protezioni di inclusione. Inoltre, prova a scegliere nomi che rendono improbabili gli scontri. Quindi sembra che le esercitazioni della tua classe siano sbagliate su almeno due punti. Vedi questo humorous article per esempio.

0

Un argomento per inserire le protezioni di inclusione nel file che include l'intestazione, piuttosto che nell'intestazione stessa, è che se il file è già stato incluso, il compilatore (in particolare il preprocessore) non deve aprire e leggere il file include di nuovo.

Questo è un argomento debole. In pratica, il tempo risparmiato è banale e il potenziale di errore è grande.

Nel tuo esempio:

#ifndef HEADER_H 
#include "header.h" 
... 
#endif 

non si mostra a noi la #define HEADER_H. È da qualche parte in header.h?Se è così, come fai a sapere che l'autore ha scelto di utilizzare header.hHEADER_H come il nome della macro include guard? Cosa succede se cambia in qualcos'altro dopo?

Se si decide di mettere l'inclusione di guardia nel file tra cui, è necessario definire la macro anche lì:

#ifndef HEADER_H 
#include "header.h" 
#define HEADER_H 
#endif 

Ma, come altre risposte hanno già detto, è molto meglio per mettere il guardia nell'intestazione stessa:

header.h:

#ifndef HEADER_H 
#define HEADER_H 
/* contents of header.h */ 
#endif 

e quindi l'inclusione ha semplicemente:

#include "header.h" 

e ha una informazione in meno di cui preoccuparsi.