Novo no C ++! Então, eu estava lendo isso: http://www.learncpp.com/cpp-tutorial/110-a-first-look-at-the-preprocessor/
Protetores de cabeçalho
Como os arquivos de cabeçalho podem incluir outros arquivos de cabeçalho, é possível acabar na situação em que um arquivo de cabeçalho é incluído várias vezes.
Então, fazemos diretrizes de pré-processador para evitar isso. Mas não tenho certeza - por que o compilador não pode simplesmente ... não importar a mesma coisa duas vezes?
Dado que os protetores de cabeçalho são opcionais (mas aparentemente uma boa prática), quase me faz pensar que existem cenários em que você deseja importar algo duas vezes. Embora eu não consiga pensar em nenhum desses cenários. Alguma ideia?
#pragma once
que diz ao compilador para incluir apenas esse arquivo uma vez.Respostas:
Eles podem, como mostra os novos idiomas que o fazem.
Mas uma decisão de design foi tomada há muitos anos (quando o compilador C era múltiplo em estágios independentes) e agora, para manter a compatibilidade, o pré-processador precisa agir de uma certa maneira para garantir que o código antigo seja compilado conforme o esperado.
Como o C ++ herda a maneira como processa os arquivos de cabeçalho de C, ele manteve as mesmas técnicas. Estamos apoiando uma antiga decisão de design. Mas mudar a maneira como funciona é muito arriscado. Muitos códigos podem potencialmente quebrar. Então agora temos que ensinar aos novos usuários do idioma como usar os protetores de inclusão.
Existem alguns truques com os arquivos de cabeçalho nos quais você foi deliberadamente incluído várias vezes (isso realmente fornece um recurso útil). Embora, se redesenhamos o paradigma do zero, poderíamos tornar isso a maneira não padrão de incluir arquivos.
fonte
Caso contrário, não seria tão expressivo, uma vez que eles escolheram manter a compatibilidade com C e, assim, continuar com um pré-processador em vez de um sistema de empacotamento tradicional.
Uma coisa que me vem à mente é que eu tinha um projeto que era uma API. Eu tinha dois arquivos de cabeçalho
x86lib.h
ex86lib_internal.h
. Como o interno era enorme, separei os bits "públicos" para x86lib.h, para que os usuários não precisassem reservar tempo extra para compilar.Isso introduziu um problema engraçado com dependências, portanto, acabei tendo um fluxo que era assim no x86lib_internal
Eu não diria que era a melhor maneira de fazer isso, mas conseguiu o que eu queria.
fonte
Uma dificuldade com a exclusão automática de cabeçalho duplicado é que o padrão C é relativamente silencioso quanto ao significado dos nomes de arquivos incluídos. Por exemplo, suponha que o arquivo principal que está sendo compilado contenha diretivas
#include "f1.h"
e#include "f2.h"
, e os arquivos encontrados para essas diretivas contenham#include "f3.h"
. Sef1.h
ef2.h
estiver em diretórios diferentes, mas foram encontrados pela pesquisa de caminhos de inclusão, não seria claro que as#include
diretivas desses arquivos foram destinadas a carregar o mesmof3.h
arquivo ou diferentes.As coisas pioram ainda mais se adicionarmos as possibilidades de incluir arquivos, incluindo caminhos relativos. Em alguns casos em que os arquivos de cabeçalho usam caminhos relativos para diretivas de inclusão aninhadas, e onde se deseja evitar alterações nos arquivos de cabeçalho fornecidos, pode ser necessário duplicar um arquivo de cabeçalho em vários locais na estrutura de diretórios de um projeto. Embora existam várias cópias físicas desse arquivo de cabeçalho, elas devem ser consideradas semanticamente como se fossem um único arquivo.
Se a
#pragma once
diretiva permitisse que um identificador seguisseonce
, com a semântica que o compilador deve ignorar o arquivo se o identificador corresponder a um de uma#pragma once
diretiva encontrada anteriormente , a semântica seria inequívoca; um compilador que poderia dizer que uma#include
diretiva carregaria o mesmo#pragma once
arquivo marcado como um anterior, poderia economizar um pouco de tempo ignorando o arquivo sem abri-lo novamente, mas essa detecção não seria semanticamente importante, pois o arquivo seria ignorado se ou não, o nome do arquivo foi reconhecido como uma correspondência. No entanto, não conheço nenhum compilador trabalhando dessa maneira. Ter um compilador observando se um arquivo corresponde ao padrão#ifndef someIdentifier / #define someIdentifier / #endif [for that ifndef] / nothing following
e tratando algo equivalente ao acima#pragma once someIdentifier
sesomeIdentifier
permanece definido, é essencialmente tão bom.fonte