Por que #ifndef e #define são usados ​​nos arquivos de cabeçalho C ++?

496

Eu tenho visto um código como este geralmente no início dos arquivos de cabeçalho:

#ifndef HEADERFILE_H
#define HEADERFILE_H

E no final do arquivo é

#endif

Qual é o propósito disso?

Asad Khan
fonte
36
+1 - Eu também tive a mesma dúvida e obtive muito mais boas respostas aqui, pode ser útil para futuros visitantes: stackoverflow.com/q/3246803/1134940
Abid Rahman K
6
Quero acrescentar a isso que você também pode usar #pragma uma vez , é tudo o que você precisa fazer e serve ao mesmo objetivo que o ifndef. Para comparação dos dois, consulte: stackoverflow.com/questions/1143936/…
Dimension
3
Melhor mencionar o que #pragmaé: ele ativa um recurso específico do compilador. Embora #pragma onceseja muito amplamente apoiada, é fora do padrão.
Potatoswatter
3
@Dimension: A própria documentação do GNU ( info cppou veja aqui ) diz "ela não é reconhecida por todos os pré-processadores, portanto você não pode confiar nela em um programa portátil". E o GNU cpp otimiza o #ifndefidioma comum e portátil, tornando-o tão eficiente quanto #pragma once.
Keith Thompson
3
Algumas coisas a considerar: não use um nome de macro que comece com um sublinhado; esses identificadores são reservados para a implementação. Mais sutilmente, #ifndef HEADERFILE_Hpode violar o namespace da implementação do nome do cabeçalho que acontece com o início E; os identificadores que começam com Ee um dígito ou letra maiúscula são reservados para <errno.h>. Eu sugiro #ifndef H_HEADERFILE.
Keith Thompson

Respostas:

527

Esses são chamados de #include guardas .

Uma vez incluído o cabeçalho, ele verifica se um valor único (neste caso HEADERFILE_H) está definido. Então, se não estiver definido, ele será definido e continuará no restante da página.

Quando o código é incluído novamente, o primeiro ifndeffalha, resultando em um arquivo em branco.

Isso evita a declaração dupla de qualquer identificador, como tipos, enumerações e variáveis ​​estáticas.

LiraNuna
fonte
1
Koning Baard XIV: VC tem mesmo um #pragma onceque faz o mesmo :-)
Joey
95
Também previne inclusões recursiva ... Imagine "alice.h" inclui "bob.h" e "bob.h" inclui "alice.h" e eles não têm incluem guardas ...
Kevin Dungs
@ Kevin: é isso que eu quero dizer. Eu queria manipular um formulário que foi aberto pelo formulário para manipular. Isso gerou muitos erros e eu não sabia o que fazer. Eu desisti =)
6
@ :Οеу: #pragma oncenão é portátil; o #ifndefidioma comum é recomendado.
21413 Keith Thompson
2
@CIsForCookies Insira "regra de uma definição" no seu mecanismo de pesquisa favorito.
David Schwartz
33
#ifndef <token>
/* code */
#else
/* code to include if the token is defined */
#endif

#ifndefverifica se o token fornecido foi #definedanteriormente no arquivo ou em um arquivo incluído; caso contrário, inclui o código entre ele e a declaração de fechamento #elseou, se não #elsehouver, é frequentemente usado para tornar os arquivos de cabeçalho idempotentes, definindo um token depois que o arquivo foi incluído e verificando se o token não foi definido na parte superior do arquivo.#endif#ifndef

#ifndef _INCL_GUARD
#define _INCL_GUARD
#endif
Roy
fonte
4
Identificadores começando com um sublinhado são reservados; você não deve defini-los você mesmo. Use algo parecido #ifndef H_HEADER_NAME.
Keith Thompson
5
Eu sei que este é um comentário antigo, mas, na verdade, a restrição de sublinhado se aplica apenas a "identificadores externos" - identificadores que podem acabar na tabela de símbolos do objeto compilado, ou seja, variáveis ​​globais e nomes de funções. Não se aplica a nomes de macro.
Stu
1
O comentário de Stu é verdadeiro? Acabei de ler stackoverflow.com/questions/228783/… e agora não tenho tanta certeza.
Will
10

Isso impede a inclusão múltipla do mesmo arquivo de cabeçalho várias vezes.

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

Suponha que você incluiu esse arquivo de cabeçalho em vários arquivos. Portanto, a primeira vez que __COMMON_H__ não for definida, ela será definida e o arquivo de cabeçalho será incluído.

Da próxima vez que __COMMON_H__ for definido, não será incluído novamente.

Sandeep_black
fonte
1

Eles são chamados ifdef ou incluem guardas.

Se estiver escrevendo um pequeno programa, pode parecer que não é necessário, mas à medida que o projeto cresce, você pode intencional ou involuntariamente incluir um arquivo várias vezes, o que pode resultar em um aviso de compilação como a variável já declarada.

#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 não for declarado, o que significa que #ifndef gera true, apenas a parte entre #ifndef e #endif executada de outra forma não. Isso impedirá de declarar novamente os identificadores, enumerações, estrutura, etc.

Mohit Jain
fonte