2009-02-28 2 views
41

Я рассмотрел вопросы How to use include directive correctly и C++ #include semantics и ни адреса этого - и не другие предложенные SO, когда я напечатал название ...Каковы преимущества относительного пути, например «../include/header.h» для заголовка?

Что, если таковой имеется, преимущество написания:

#include "../include/someheader.h" 
#include "../otherdir/another.h" 

по сравнению с использованием только обычного имени файла:

#include "someheader.h" 
#include "another.h" 

или, возможно относительное имя без «..»:

#include "include/someheader.h" 
#include "otherdir/another.h" 

Проблемы, которые я вижу, являются:

  • Вы не можете переместить заголовок, не заботясь о том, какие исходные файлы включают его.
  • Вы можете получить очень длинные пути для заголовков в зависимостях и отчетах об ошибках. У меня был один сегодня с «../dir1/include/../../include/../dir2/../include/header.h».

Единственная заслуга, я могу видеть, что в то время как вам не нужно перемещать файлы, вы можете быть в состоянии уйти без всегда использовать «-I» директивы, чтобы найти заголовки, но потеря гибкости и сложность компиляции в под-подкаталогах и т. д., кажется, перевешивает выгоду.

Итак, я не вижу преимущества?


Спасибо за ввод. Я думаю, что консенсус в том, что нет никаких существенных преимуществ для нотации, использующей «..», которую я пропускаю. В общем, мне нравится нотация «где-то/header.h»; Я использую его в новых проектах. Тот, над которым я работаю, является чем-то новым.

Одна из проблем состоит в том, что существуют различные наборы заголовков, часто с префиксом, такие как rspqr.h, rsabc.h, rsdef.h, rsxyz.h. Все они связаны с кодом в каталоге rsmp, но некоторые из заголовков находятся в rsmp, а другие находятся в центральной директории include, в которой нет подкаталогов, таких как rsmp. (И повторите для разных других областей кода, есть заголовки в нескольких местах, которые необходимо случайным образом выполнять с помощью других битов кода.) Перемещение материала вокруг является серьезной проблемой, потому что код стал настолько запутанным на протяжении многих лет. И make-файлы несовместимы, в которых предусмотрены опции -I. В целом, это печальная история о не столь благожелательном пренебрежении в течение нескольких десятилетий. Фиксация всего этого, не нарушая ничего, будет длительной, утомительной работой.

+0

Вы, кажется, знаете все факторы, поэтому это не вопрос. – shoosh

+0

Я проверяю, есть ли льготы, которые я забыл (потому что я ненавижу нотацию, но страдаю от этого на работе). У меня меньше проблем с обозначением без «..» в нем. –

+0

Это (с использованием относительных путей) имеет тенденцию приводить к огромным головным болям при использовании отдельной сборки. I.e cd yourproject; mkdir build; cd build; ../configure && make - Если вы собираетесь продолжать поддерживать код, возможно, стоит исправить это. –

ответ

28

Я предпочитаю синтаксис пути, так как он очень четко определяет, какое пространство имен или модуль принадлежит файлу заголовка.

#include "Physics/Solver.h" 

Очень самоописывается, не требуя, чтобы каждый модуль префикс их имени заголовочным файлам.

Я почти никогда не пользуюсь "..Синтаксис, хотя вместо этого у меня есть мой проект, в котором указаны правильные базовые местоположения.

1

Потому что тогда вы помещаете файл относительно корня проекта, и когда вы проверяете его на исходный элемент управления, а другой разработчик проверяет его в другом месте на своей локальной системе, все еще работает.

+3

Я рассматриваю это как аргумент против абсолютных имен путей, но я не спрашивал об этом (они однозначно плохо AFAIAC). Я не уверен, что это аргумент для - или против - любого из вариантов относительного имени. –

2

Подумайте о том, что ваше исходное дерево является вложенным пространством имен, а путь включения - вытаскивать каталоги в корень этого пространства имен. один из формирования логического пространства имен для вашего кода базы независимо от того, как организован код на диске

Я хотел бы избежать пути, как:.

  • "include/foo/bar.h" - «включить» кажется нелогичным и излишним
  • "../foo/bar.h"- «..» предполагает относительное местоположение и является хрупким
  • "bar.h" - если bar.h не находится в текущем каталоге, это загрязняет глобальное пространство имен и запрашивает неоднозначность.

Лично я склонен добавить к моим проектам следующий путь: путь - "..;../..;../../..;../../../..".

Это позволяет применить свое правило скрытия к вашему #include и разрешить свободу передвижения заголовков без нарушения кода. Конечно, это за счет введения риска привязки к неправильному заголовочному файлу, если вы не будете осторожны, поскольку неполные имена могут быть (или становятся со временем) неоднозначными.

Я стараюсь полностью квалифицировать #include s в публичных заголовках, поэтому третьим лицам, покупающим мой код, не нужно добавлять "..;../..;../../..;../../../.." к их проекту - это просто удобство для моего личного кода и системы сборки.

+1

Какова цель ';' на вашем пути? – Royi

+1

«;» является разделителем путей в окнах, в частности, как вы предоставляете набор каталогов для поиска в Visual Studio. –

+0

Не могли бы вы уточнить. Я не уверен, что понял. Спасибо. – Royi

8

IANALL, но я не думаю, что вы должны размещать .. в реальных исходных файлах C или C++, потому что это не переносимо, и стандарт не поддерживает его. Это похоже на использование \ на Windows. Делайте это только в том случае, если ваш компилятор не может работать с каким-либо другим методом.

+3

Хорошая точка. Стандарт даже не гарантирует, что вы можете использовать перемотки вперед. «Реализация обеспечивает уникальные сопоставления для последовательностей, состоящих из одного или нескольких недигитов (lex.name), за которыми следует период (.) И один недигит». Он определяет недигит как в основном [_a-zA-Z] или \ uNNNN. – bk1e

+0

Это правда, но программное обеспечение, о котором идет речь, уже несколько лет готовит на широком спектре платформ (более двадцати из них), поэтому это скорее теоретическая, чем практическая ответственность. –

+1

Нулевые google хиты для IANALL. Я предполагаю, что это «я не юрист языка»? –

22

Проблема с #include "../include/header.h" заключается в том, что она часто срабатывает случайно, а затем, казалось бы, несвязанное изменение заставит ее перестать работать позже.

Для примера рассмотрит следующую схему источника:

./include/header.h 
./lib/library.c 
./lib/feature/feature.c 

И давайте предположим, что вы запускаете компилятор с включаемым путем -I. -I./lib. Что происходит?

  • ./lib/library.c можно сделать #include "../include/header.h", что имеет смысл.
  • ./lib/feature/feature.c также можно сделать #include "../include/header.h", даже если это не имеет смысла. Это связано с тем, что компилятор попытается установить директиву #include относительно местоположения текущего файла, и если это не удастся, он попытается установить директиву #include относительно каждой записи -I в пути #include.

Кроме того, если убрать -I./lib из #include пути, то вы нарушаете ./lib/feature/feature.c.

я нахожу что-то вроде следующего более предпочтительным:

./projectname/include/header.h 
./projectname/lib/library.c 
./projectname/lib/feature/feature.c 

Я не хотел бы добавить любой включаемый путь записей, кроме -I., а затем и library.c и feature.c будет использовать #include "projectname/include/header.h". Предполагая, что «имя проекта», вероятно, будет уникальным, это не должно приводить к столкновениям имен или неоднозначностям в большинстве случаев. Вы также можете использовать путь include и/или make VPATH, чтобы разделить физический макет проекта по нескольким каталогам, если это абсолютно необходимо (например, для создания специально созданного кода для конкретной платформы; это то, что действительно ломается, когда вы используете #include "../../somefile.h").

+1

Да, эта вещь с использованием «projectname/include/header.h» была тем, что я использовал в своем последнем проекте (но начал с include/вместо). Я всегда ставил только один -I, который указывает на include/path, а затем я включаю на основе этого. но я еще не анализировал проблемы «..». У вас есть хорошие моменты. –

1

Другая проблема с окнами с относительными путями - MAX_PATH. Это вызовет проблемы компиляции, когда, например, кросс-компиляция для android, и ваш путь увеличивается больше 260.

Смежные вопросы