Perché #ifndef e #define sono utilizzati nei file di intestazione C ++?


496

Ho visto codice come questo di solito all'inizio dei file di intestazione:

#ifndef HEADERFILE_H
#define HEADERFILE_H

E alla fine del file è

#endif

Qual è lo scopo di questo?


36
+1 - Anch'io avevo lo stesso dubbio, e ho ottenuto una risposta molto più buona qui, può essere utile per i futuri visitatori: stackoverflow.com/q/3246803/1134940
Abid Rahman K

6
Voglio aggiungere a questo che puoi anche usare #pragma una volta , questo è tutto ciò che devi fare e ha lo stesso scopo di ifndef. Per un confronto tra i due, vedere: stackoverflow.com/questions/1143936/…
Dimensione

3
Meglio menzionare cos'è #pragma: attiva una funzione specifica del compilatore. Anche se #pragma onceè molto ampiamente supportato, è non standard.
Potatoswatter,

3
@Dimension: la documentazione di GNU ( info cppo guarda qui ) dice "non è riconosciuta da tutti i preprocessori, quindi non puoi fare affidamento su di essa in un programma portatile". E GNU cpp ottimizza il #ifndeflinguaggio comune e portatile, quindi è efficiente come #pragma once.
Keith Thompson,

3
Alcune cose da considerare: non usare un nome di macro che inizia con un trattino basso; tali identificatori sono riservati all'implementazione. Più sottilmente, #ifndef HEADERFILE_Hpuò violare lo spazio dei nomi dell'implementazione del nome dell'intestazione che inizia con E; gli identificatori che iniziano con Ee una cifra o una lettera maiuscola sono riservati a <errno.h>. Io suggerisco #ifndef H_HEADERFILE.
Keith Thompson,

Risposte:


527

Quelli sono chiamati #include guards .

Una volta inclusa l'intestazione, controlla se HEADERFILE_Hviene definito un valore univoco (in questo caso ). Quindi, se non è definito, lo definisce e continua fino al resto della pagina.

Quando il codice viene incluso di nuovo, il primo ha ifndefesito negativo, con conseguente file vuoto.

Ciò impedisce la doppia dichiarazione di qualsiasi identificatore come tipi, enumerazioni e variabili statiche.


1
Koning Baard XIV: VC ha anche una #pragma onceche fa lo stesso :-)
Joey,

95
Inoltre previene le inclusioni ricorsive ... Immagina che "alice.h" includa "bob.h" e "bob.h" includa "alice.h" e non hanno guardie incluse ...
Kevin Dungs

@ Kevin: questo è ciò che intendo. Volevo manipolare un modulo che è stato aperto dal modulo per manipolare. Mi ha dato molti errori e non sapevo cosa fare. Ho rinunciato =)

6
@ Јοеу: #pragma oncenon è portatile; #ifndefsi raccomanda il linguaggio comune .
Keith Thompson,

2
@CIsForCookies Inserisci una "regola di definizione" nel tuo motore di ricerca preferito.
David Schwartz,

33
#ifndef <token>
/* code */
#else
/* code to include if the token is defined */
#endif

#ifndefcontrolla se il token dato è stato #definedprecedentemente nel file o in un file incluso; in caso contrario, include il codice tra esso e la chiusura #elseo, se non #elseè presente, l' #endifistruzione. #ifndefviene spesso utilizzato per rendere idempotenti i file di intestazione definendo un token una volta che il file è stato incluso e verificando che il token non sia stato impostato nella parte superiore di quel file.

#ifndef _INCL_GUARD
#define _INCL_GUARD
#endif

4
Gli identificatori che iniziano con un trattino basso sono riservati; non dovresti definirli tu stesso. Usa qualcosa di simile #ifndef H_HEADER_NAME.
Keith Thompson,

5
So che questo è un vecchio commento, ma in realtà la limitazione di sottolineatura si applica solo agli "identificatori esterni", identificatori che potrebbero finire nella tabella dei simboli dell'oggetto compilato, ovvero variabili globali e nomi di funzioni. Non si applica ai nomi di macro.
Stu,

1
Il commento di Stu è vero? Ho appena letto stackoverflow.com/questions/228783/… e ora non ne sono così sicuro.
Will,

10

Ciò impedisce l'inclusione multipla dello stesso file di intestazione più volte.

#ifndef __COMMON_H__
#define __COMMON_H__
//header file content
#endif

Supponiamo di aver incluso questo file di intestazione in più file. Pertanto, la prima volta che __COMMON_H__ non viene definito, verrà definito e verrà incluso il file di intestazione.

La prossima volta che __COMMON_H__ viene definito, quindi non includerà di nuovo.


1

Si chiamano ifdef o includono guardie.

Se si scrive un piccolo programma, potrebbe sembrare che non sia necessario, ma man mano che il progetto cresce, è possibile includere intenzionalmente o involontariamente un file più volte, il che può comportare un avviso di compilazione come una variabile già dichiarata.

#ifndef checks whether HEADERFILE_H is not declared.
#define will declare HEADERFILE_H once #ifndef generates true.
#endif is to know the scope of #ifndef i.e end of #ifndef

Se non viene dichiarato, il che significa che #ifndef genera true, solo la parte tra #ifndef e #endif viene eseguita altrimenti. Ciò impedirà di dichiarare nuovamente identificatori, enum, struttura, ecc.

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.