Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 54
Текст из файла (страница 54)
Эффект от неименованных пространств имен очень близок к внутренней компоновке. Например: //файл !йе!.с: патвврасе ( с!а55 Х ( /* ° ° ° */ ) ' коЫ/'( ); !пг 1; У... ) У файл !йе2.с: сйтХ(/* ... */ ): коЫ у" ( ); !п! г'; // ... Здесь функция!() изЯ!е1. с не та же самая, что !() из Ь(е2.с. Использовать одинаковое имя, являющееся локальным для некоторой единицы трансляции, и обозначающее сущности с внешней компоновкой в других единицах трансляции— значит нарываться на неприятности. В языке С и в более ранних версиях С++ ключевое слово в!а!ус означает (и это может привести к путанице) «использовать внутреннюю компоновку» (5В.2.3). Не применяйте вгаг(с иначе как внутри функций (57.1.2) или классов Ц10.2.4). 9.2.1. Заголовочные файлы Типы во всех объявлениях одной и той же сущности должны быть согласованы.
Это означает, что исходный код, подаваемый на вход компилятору и позднее собираемый в единое целое компоновщиком, должен быть согласован. Простой (хотя и несовершенный) метод достижения согласованности объявлений в разных единицах трансляции состоит в применении директив () !ис(иИе Ьеаг(его!ел для внесения интерфейсной информации в исходные файлы с исполняемым кодом и/или определением данных.
Механизм директив () !пс!иНе является простым текстовым средством, позволяющим собрать воедино разные фрагменты исходного кода в единицу (файл) компиляции. Директива Ыпс(ийв 'Цо Ьв (пс(иова'" замещает строку, содержащую ()упс!иг!е, на содержимое файла го Ье /пс!идей. Файл должен содержать код на С++, так как он поступит на обработку компилятором языка С++.
Имена стандартных библиотечных заголовочных файлов заключайте в угловые скобки < и > (а не в кавычки). Например: Ипс!ийв <тгагеат> //нз стандартного каталога заголовочных файлов ()!пс!иае "туйеайег.Ь" //нз текущего каталога Глава 9. Исходные файлы и программы 258 Обратите внимание на то, что пробелы внутри угловых скобок или кавычек существенны для выполнимости директивы №тпсйм(е: Ыпс(ийе < 1омгеат > У не будет найден файл <(ояггеат> Необходимость компилировать файл каждый раз при его включении куда-либо может показаться несколько экстравагантной, но заголовочные файлы в типичном случае содержат только объявления, а не код, требующий серьезного анализа со стороны компилятора.
Более того, все современные реализации обеспечивают некоторую форму лредкомлиляции (ргесотр!1!ля) заголовочных файлов для минимизации усилий, требуемых для их повторных компиляций. Согласно эмпирическому правилу заголовочные файлы могут содержать следующие элементы: Данное эмпирическое правило не является требованием языка. Оно просто формулирует разумные способы использования заголовочных файлов (директив №1пс!и!№е) для выражения физической структуры программы. С другой стороны, заголовочные фалы не долмсны содержать следующего: Определения обычных функций Определения данных Определения агрегатов , Неименованные пространства имен , 'Экспортируемые определения шаблонов сваг ее1 (сваг* р) ( ге!игл "рев; ) гпг а; зйот гЫ(] = (1,1,3) т пагпеярасе (1*...
*! ) ехрогг гетр(а!с<егозя Т>3(Т!) (l*...*/) Обычно, заголовочные файлы имеют расширение . й, а файлы, содержащие определения функций и/или данных, имеют расширение .с. Поэтому на них часто ссылаются как на ". й файлы" или ". с файлы", соответственно. Также в ходу расширения . С, .схх, .срр и .сс. В руководстве к вашему компилятору об этом должно быть сказано со всей определенностью. Причина, по которой в заголовочные файлы рекомендуется включать определения простых констант, а определения агрегатов включать не рекомендуется, заключается в том, что реализациям трудно избежать репликации агрегатов в не- ] Именованные пространства имен Определения типов Объявления шаблонов Определения шаблонов Объявления функций Определения встроенных функций Объявления данных ~ Определения констант ( Перечисления ] Объявления имен Директивы включения Макроопределения Директивы условной компиляции Комментарии патезрасе ]т'( l * ...* l ) тгиш Ройи ((п! х, у; ); гетр(аге<сгат Т> с(аяя Ут гетр1аге<сгат Т> с(азз И(!*...
*/ ) ех!егп №п! яи№ел (солт сваг* ); шипе слегшее!(сваг* р) ( ге!игп *рве; ) ехгегп ии а; сопя!)тоа! р1 = 3. 141593; епит Егей! ( геа, уе1!оы, егееп ); с1азз Ма!гЫ; № шс!ийе <агеог1!йт> № верше МЕ!то101т' 12 № (!)1еТ ср!изр!из ] /* проверка на конец файла *т' 9.2. Компоновка (!)пйаце) 9.2.2. Заголовочные файлы стандартной библиотеки Средства стандартной библиотеки описаны в наборе стандартных заголовочных файлов 51б.1.2). В именах этих заголовочных файлов расширения не используются; заголовочные же они потому, что включаются в текст программы с помошью №йвс1иИе <... > (стандартные заголовки требуют угловых скобок, а не кавычек).
Отсутствие суффикса . й не отражает способа хранения содержимого этих файлов; например, содержимое <гпар> может располагаться в файле тар. А из стандартного каталога. Более того, вообше не требуется, чтобы стандартные заголовки хранились традиционным образом. Конкретные реализации могут по максимуму использовать свои знания о стандартной библиотеке и ее заголовках, реализуя оптимизированные способы их хранения и представления. Например, компилятор, отталкиваясь от своих знаний о встроенном характере стандартной математической библиотеки (522.3), может трактовать директиву №1пс1иИе <сгпагй> просто как некий логический переключатель (тумблер), открываюший возможность применения в программе стандартных математических функций, а вовсе не как требование чтения конкретного файла. Для каждого стандартного заголовка <Хй> языка С имеется соответствующий стандартный заголовок <сХ> языка С++.
Например, №1пс1иИе <свп№1о> обеспечивает то же, что и №1пс1иг№е <вайо. й>. В типичном случае, содержимое а»11о. й выглядит следуюшим образом: й' только для Сьм компиляторов 69.2.4) )г' стандарт. биб-ка определена в прост. имен згд 1ВВ 2.9) №1)г)е) ср)ивр!ив патеврасе вЫ( У функции зн)1о имеют компоновку языка С (з9.2.4) екгегп "С" ) №епй~ !* *) тг рг(пг)'(сопле сйаг* ...
); !* */ №1Яе1 ср1ивр1ив ) й ... ивтл вга:: рггп(1г У... №епй~ й' делает ргтпб' доступным в глобальном пространстве имен скольких единицах трансляции. К тому же, более простые конструкции встречаются чаще, а потому для них важнее генерировать более качественный машинный код. Будет разумным не переусердствовать в изобретении слишком «умных» случаев использования директив №1пс1ие(е. Мои рекомендации сводятся к тому, чтобы включать лишь полные объявления и определения в глобальной области видимости, в блоках спецификации компоновки и в пространствах имен для конвертирования старого кода (59.2.2). Как всегда, стоит избегать магических фокусов с макроопределениями. Я, например, страшно не люблю отслеживать ошибки неожиданных результатов макроподстановок из косвенно включаемых заголовочных файлов, о которых я даже, ровным счетом, ничего и не слышал.
260 Глава 9. Исходные файлы и программы Таким образом, реальное содержимое (объявления) для обоих языков одинаковое, а пространства имен и режимы компоновки введены так, что этот файл можно использовать из программ на С и С++. 9.2.3. Правило одного определения 'Каждый класс, перечисление, шаблон и т.д. должны быть определены в программе ровно один раз. С практической точки зрения это означает, что должно существовать единственное определение, например, класса, находящееся в каком-либо одном файле.
К сожалению, языковые правила не столь просты. Например, определение класса можно сформировать через макроопределение (б-р-р!), или определение класса может быть текстуально включено с помощью директив ))!пс1и«!е сразу в несколько исходных файлов (59.2.1). Еще хуже то, что файл вообще не является концепцией языков С/С++; могут сущеспювать реализации, не использующие файлы для хранения программ. В результате правило стандарта, гласящее о том, что определения классов, шаблонов и т.д. должны быть уникальными, на самом деле формулируется сложнее и тоньше. Это правило называют «правилом одного определения» («!Ье опе-де!)п!!!оп ги1е» вЂ” сокращенно 01И): два определения класса, шаблона или встраиваемой функции принимаются за экземпляры одного и того же уникального определения тогда и только тогда, если: 1.
Они находятся в разных единицах трансляции. 2. Они полексемно идентичны. 3. Смысл этих лексем одинаковый в обеих единицах трансляции. Например: // файл 1)1е !. с: зпис! Я !!и! а; сааг Ь! ); соЫ 1"(Я*); У файл 61е2,с: зггисгЯ (яма; сьаг Ь; ); гоЫ1(Я* р) 1 l* ... *l ) Правило 01Ж говорит, что данный пример корректен, и что определения Я в обоих исходных файлах ссылаются на один и тот же класс (структуру). Конечно же, крайне неразумно дважды записывать одно и то же определение таким образом. Кто-нибудь, модифицируя файлЯ1е2.