inclui guarda - include guard

Nas linguagens de programação C e C ++ , um #include guard , às vezes chamado de macro guard , header guard ou file guard , é uma construção particular usada para evitar o problema de dupla inclusão ao lidar com a diretiva include .

O pré- processador C processa as diretivas do formulário #include <file>em um arquivo de origem , localizando o associado fileno disco e transcluindo ("incluindo") seu conteúdo em uma cópia do arquivo de origem conhecido como unidade de tradução , substituindo a diretiva de inclusão no processo. Os arquivos incluídos a esse respeito são geralmente arquivos de cabeçalho , que normalmente contêm declarações de funções e classes ou estruturas . Se certas construções de linguagem C ou C ++ são definidas duas vezes , a unidade de tradução resultante é inválida . #include guardas evita que esta construção errônea surja pelo mecanismo de dupla inclusão.

A adição de #include guardas a um arquivo de cabeçalho é uma maneira de tornar esse arquivo idempotente . Outra construção para combater a inclusão dupla é #pragma uma vez , que não é padrão, mas é quase universalmente compatível entre os compiladores C e C ++ .

Inclusão dupla

Exemplo

O código C a seguir demonstra um problema real que pode surgir se #include guardas estiverem faltando:

Arquivo "grandparent.h"

struct foo {
    int member;
};

Arquivo "parent.h"

#include "grandparent.h"

Arquivo "child.c"

#include "grandparent.h"
#include "parent.h"

Resultado

struct foo {
    int member;
};
struct foo {
    int member;
};

Aqui, o arquivo "child.c" inclui indiretamente duas cópias do texto no arquivo de cabeçalho "grandparent.h". Isso causa um erro de compilação , pois o tipo de estrutura fooserá definido duas vezes. Em C ++, isso seria chamado de violação da regra de definição única .

Uso de #include guardas

Exemplo

Nesta seção, o mesmo código é usado com a adição de #include guardas. O pré- processador C pré- processa os arquivos de cabeçalho, incluindo e posteriormente pré-processando-os recursivamente . Isso resultará em um arquivo fonte correto, como veremos.

Arquivo "grandparent.h"

#ifndef GRANDPARENT_H
#define GRANDPARENT_H

struct foo {
    int member;
};

#endif /* GRANDPARENT_H */

Arquivo "parent.h"

#include "grandparent.h"

Arquivo "child.c"

#include "grandparent.h"
#include "parent.h"

Resultado

struct foo {
    int member;
};

Aqui, a primeira inclusão de "grandparent.h" tem a macro GRANDPARENT_Hdefinida. Quando "child.c" inclui "grandparent.h" na segunda vez, como o #ifndefteste retorna false, o pré-processador salta para o #endif, evitando assim a segunda definição de struct foo. O programa é compilado corretamente.

Discussão

Diferentes convenções de nomenclatura para a macro de guarda podem ser usadas por diferentes programadores . Outras formas comuns do exemplo acima incluem GRANDPARENT_INCLUDED, CREATORSNAME_YYYYMMDD_HHMMSS(com a informação de tempo apropriada substituída) e nomes gerados a partir de um UUID . (No entanto, nomes que começam com um sublinhado e uma letra maiúscula ou qualquer nome que contenha sublinhado duplo, como _GRANDPARENT__He __GRANDPARENT_H, são reservados para a implementação da linguagem e não devem ser usados ​​pelo usuário.)

Obviamente, é importante evitar a duplicação do mesmo nome de macro de inclusão-guarda em arquivos de cabeçalho diferentes, pois incluir o primeiro impedirá que o segundo seja incluído, levando à perda de quaisquer declarações, definições inline ou outros #includes no 2º cabeçalho.

Dificuldades

Para que #include guardas funcionem corretamente, cada guarda deve testar e definir condicionalmente uma macro de pré-processador diferente. Portanto, um projeto que usa #include guardas deve elaborar um esquema de nomenclatura coerente para seus guardas de inclusão e certificar-se de que seu esquema não entre em conflito com o de quaisquer cabeçalhos de terceiros que usa, ou com os nomes de quaisquer macros visíveis globalmente.

Por esse motivo, a maioria das implementações C e C ++ fornecem uma #pragma oncediretiva fora do padrão . Esta diretiva, inserida no topo de um arquivo de cabeçalho, irá garantir que o arquivo seja incluído apenas uma vez. A linguagem Objective-C (que é um superconjunto de C) introduziu uma #importdiretiva, que funciona exatamente como #include, exceto que inclui cada arquivo apenas uma vez, evitando assim a necessidade de #include guardas.

Veja também

Referências

  1. ^ Padrão C ++ (ISO / IEC 14882) seção 17.4.3.1.2 / 1
  2. Padrão ^ C (ISO / IEC 9899) seção 7.1.3 / 1.
  3. ^ "Objetivo C: Definindo Classes" . developer.apple.com . 17/09/2014 . Página visitada em 03/10/2018 .

links externos