Dlaczego #ifndef i #define są używane w plikach nagłówkowych C ++?

495

Kod taki widziałem zwykle na początku plików nagłówkowych:

#ifndef HEADERFILE_H
#define HEADERFILE_H

A na końcu pliku jest

#endif

Jaki jest tego cel?

Asad Khan
źródło
36
+1 - ja również miałem takie same wątpliwości i otrzymałem tutaj o wiele więcej dobrych odpowiedzi, mogą być przydatne dla przyszłych gości: stackoverflow.com/q/3246803/1134940
Abid Rahman K
6
Chcę dodać do tego, że możesz raz użyć #pragmy , to wszystko, co musisz zrobić i służy to samo celowi, co ifndef. Aby porównać oba, patrz: stackoverflow.com/questions/1143936/...
Wymiar
3
Najlepiej wspomnieć o czym #pragmajest a : aktywuje funkcję specyficzną dla kompilatora. Chociaż #pragma oncejest bardzo szeroko obsługiwany, jest niestandardowy.
Potatoswatter
3
@Dimension: własna dokumentacja GNU ( info cpplub spójrz tutaj ) mówi: „nie jest rozpoznawana przez wszystkie preprocesory, więc nie można na niej polegać w przenośnym programie”. A GNU cpp optymalizuje wspólny i przenośny #ifndefidiom, dzięki czemu jest tak samo wydajny jak #pragma once.
Keith Thompson
3
Kilka rzeczy do rozważenia: Nie używaj nazwy makra zaczynającej się od znaku podkreślenia; takie identyfikatory są zastrzeżone do realizacji. Bardziej subtelnie, #ifndef HEADERFILE_Hmoże naruszać przestrzeń nazw implementacji nazwy nagłówka zaczyna się od E; identyfikatory zaczynające się od Eoraz cyfra lub duża litera są zastrzeżone dla <errno.h>. Sugeruję #ifndef H_HEADERFILE.
Keith Thompson

Odpowiedzi:

525

Są to tak zwane strażnicy #include .

Po dołączeniu nagłówka sprawdza, czy HEADERFILE_Hzdefiniowano unikalną wartość (w tym przypadku ). Następnie, jeśli nie jest zdefiniowany, definiuje go i przechodzi do reszty strony.

Gdy kod zostanie ponownie dołączony, pierwszy ifndefnie powiedzie się, co spowoduje powstanie pustego pliku.

Zapobiega to podwójnej deklaracji jakichkolwiek identyfikatorów, takich jak typy, wyliczenia i zmienne statyczne.

LiraNuna
źródło
Koning Baard XIV: VC ma nawet to #pragma oncesamo :-)
Joey
95
Zapobiega także inkluzywnym inkluzjom ... Wyobraź sobie, że „alice.h” obejmuje „bob.h”, a „bob.h” obejmuje „alice.h” i nie mają strażników…
Kevin Dungs
@Kevin: o to mi chodzi. Chciałem manipulować formularzem, który został otwarty przez formularz do manipulacji. Ma wiele błędów i nie wiedziałem, co robić. Zrezygnowałem =)
6
@ :Οеу: #pragma oncenie jest przenośny; #ifndefzalecany jest wspólny idiom.
Keith Thompson
2
@CIsForCookies Uderz „zasadą jednej definicji” w ulubioną wyszukiwarkę.
David Schwartz
33
#ifndef <token>
/* code */
#else
/* code to include if the token is defined */
#endif

#ifndefsprawdza, czy dany token był #definedwcześniej w pliku, czy w dołączonym pliku; jeśli nie, zawiera kod między nim a końcem #elselub, jeśli nie, #elsejest to #endifinstrukcja. #ifndefjest często używany do uczynienia plików nagłówkowych idempotentnymi poprzez zdefiniowanie tokena po dołączeniu pliku i sprawdzenie, czy token nie został ustawiony na początku tego pliku.

#ifndef _INCL_GUARD
#define _INCL_GUARD
#endif
Roy
źródło
4
Identyfikatory rozpoczynające się znakiem podkreślenia są zastrzeżone; nie powinieneś ich definiować sam. Użyj czegoś takiego #ifndef H_HEADER_NAME.
Keith Thompson
5
Wiem, że to stary komentarz, ale tak naprawdę ograniczenie podkreślenia dotyczy tylko „zewnętrznych identyfikatorów” - identyfikatorów, które mogą znaleźć się w tabeli symboli skompilowanego obiektu, tj. Zmiennych globalnych i nazw funkcji. Nie dotyczy nazw makr.
Stu
1
Czy komentarz Stu jest prawdziwy? Właśnie przeczytałem stackoverflow.com/questions/228783/... i teraz nie jestem tego taki pewien.
Czy
9

Zapobiega to wielokrotnemu włączaniu tego samego pliku nagłówkowego wiele razy.

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

Załóżmy, że umieściłeś ten plik nagłówka w wielu plikach. Więc po raz pierwszy __COMMON_H__ nie zostanie zdefiniowany, zostanie zdefiniowany i dołączony plik nagłówka.

Następnym razem __COMMON_H__ zostanie zdefiniowany, więc nie będzie ponownie uwzględniany.

Sandeep_black
źródło
1

Nazywa się je ifdef lub obejmuje strażników.

Jeśli piszesz mały program, może się wydawać, że nie jest on potrzebny, ale w miarę rozwoju projektu możesz celowo lub nieumyślnie dołączyć jeden plik wiele razy, co może spowodować ostrzeżenie kompilacji, takie jak zmienna już zadeklarowana.

#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

Jeśli nie zostanie zadeklarowane, co oznacza, że ​​#ifndef generuje wartość true, wówczas tylko część między #ifndef i #endif zostanie wykonana inaczej. Zapobiegnie to ponownemu zadeklarowaniu identyfikatorów, wyliczeń, struktury itp.

Mohit Jain
źródło