Новое в C ++! Итак, я читал это: http://www.learncpp.com/cpp-tutorial/110-a-first-look-at-the-preprocessor/
Заголовок охранников
Поскольку заголовочные файлы могут включать в себя другие заголовочные файлы, возможно, что в конечном итоге файл заголовка будет включен несколько раз.
Поэтому мы делаем директивы препроцессора, чтобы избежать этого. Но я не уверен - почему компилятор не может просто ... не импортировать одно и то же дважды?
Учитывая, что средства защиты заголовков являются необязательными (но, видимо, хорошей практикой), это почти заставляет меня думать, что существуют сценарии, когда вы хотите импортировать что-то дважды. Хотя я не могу думать ни о каком таком сценарии вообще. Есть идеи?
#pragma once
который говорит компилятору включать этот файл только один раз.Ответы:
Они могут, как показывают новые языки, которые делают.
Но проектное решение было принято все эти годы назад (когда компилятор C имел несколько независимых этапов), и теперь, чтобы поддерживать совместимость, препроцессор должен действовать определенным образом, чтобы гарантировать, что старый код компилируется должным образом.
Поскольку C ++ наследует способ обработки заголовочных файлов от C, он поддерживает те же методы. Мы поддерживаем старое дизайнерское решение. Но менять способ работы слишком рискованно, поэтому большой объем кода может сломаться. Так что теперь мы должны научить новых пользователей языка, как использовать охранники.
Есть несколько хитростей с заголовочными файлами, если вы намеренно включаете его несколько раз (это действительно обеспечивает полезную функцию). Хотя, если бы мы переработали эту парадигму с нуля, мы могли бы сделать это нестандартным способом включения файлов.
источник
В противном случае это не было бы столь выразительным, учитывая, что они решили поддерживать совместимость с C и таким образом продолжать работу с препроцессором, а не с традиционной системой упаковки.
Одна вещь, которая приходит мне в голову, это то, что у меня был проект, который был API. У меня было два заголовочных файла
x86lib.h
иx86lib_internal.h
. Поскольку внутренняя часть была огромной, я разделил «публичные» биты на x86lib.h, чтобы пользователям не пришлось выделять дополнительное время для компиляции.Это породило забавную проблему с зависимостями, поэтому у меня получился такой поток в x86lib_internal
Я бы не сказал, что это был лучший способ добиться этого, но он достиг того, чего я хотел.
источник
Одна проблема с автоматическим исключением дублирующихся заголовков состоит в том, что стандарт C относительно не говорит о том, что означают имена файлов. Например, предположим, что основной компилируемый файл содержит директивы
#include "f1.h"
и#include "f2.h"
, и файлы, найденные для этих директив, содержат#include "f3.h"
. Еслиf1.h
иf2.h
находятся в разных каталогах, но были найдены путем поиска путей включения, то было бы неясно , какие#include
директивы в этих файлах предназначены для загрузки одного и того жеf3.h
файла или разных.Ситуация становится еще хуже, если добавить возможности включения файлов, включая относительные пути. В некоторых случаях, когда в файлах заголовков используются относительные пути для вложенных директив include, и если желательно избежать внесения каких-либо изменений в предоставленные файлы заголовков, может потребоваться дублирование файла заголовка в нескольких местах в структуре каталогов проекта. Даже если существует несколько физических копий этого заголовочного файла, их следует рассматривать семантически, как если бы они были одним файлом.
Если
#pragma once
директива позволила идентификатору следоватьonce
, с семантикой, которую компилятор должен пропускать файл, если идентификатор совпадает с идентификатором из ранее встречавшейся#pragma once
директивы, то семантика была бы однозначной; компилятор, который мог бы сказать, что#include
директива загрузит тот же#pragma once
файл с тегами, что и предыдущий, он мог бы сэкономить немного времени, пропуская файл, не открывая его снова, но такое обнаружение не было бы семантически важным, поскольку файл будет пропущен или не имя файла было распознано как совпадение. Однако я не знаю ни о каких компиляторах, работающих таким образом. Наличие компилятора, наблюдающего, соответствует ли файл шаблону,#ifndef someIdentifier / #define someIdentifier / #endif [for that ifndef] / nothing following
и рассматривающего такую вещь как эквивалент вышеупомянутого,#pragma once someIdentifier
еслиsomeIdentifier
остается определенным, по существу, так же хорошо.источник