Включая стиль заголовочных файлов - C ++ - PullRequest
8 голосов
/ 28 января 2010

У меня есть проект, который имеет следующую структуру каталогов.

root
--include
----module1
----module2
--src
----module1
----module2

Итак, файл, скажем foo.cpp в src/module1, должен включать как * 1006

#include "../../include/module1/foo.hpp"

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

#include <module1/foo.h>

и предоставление пути поиска включаемого файла к root/include при компиляции выглядит аккуратно. Однако я не уверен, что у этого стиля есть какие-то недостатки.

Какой из них вы предпочитаете и почему? Также вы видите какие-либо проблемы с организацией файлов вышеуказанным способом?

Ответы [ 7 ]

4 голосов
/ 28 января 2010
#include "../../include/module1/foo.hpp"

В максимально возможной степени следует избегать указания путей. Компиляторы предоставляют вам более чистую альтернативу для достижения того же. Кроме того, чистый дизайн должен следить за тем, чтобы вам не нужно было совмещать относительные пути для включения заголовков.

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

Из моей копии проекта C ++:

16.2 Включение исходного файла

2 Директива предварительной обработки вида

#include <h-char-sequence> new-line`

ищет последовательность определенные реализацией места для заголовок идентифицируется однозначно указанная последовательность между < и > разделители и вызывает замену этой директивы всей содержимое заголовка. Как местами указаны или заголовок идентифицирован определяется реализацией.

3 A директива предварительной обработки вида

# include "q-char-sequence" new-line 

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

#include <h-char-sequence> new-line`

с идентичной содержащейся последовательностью (включая> символы, если есть) из оригинальная директива.

7 Хотя реализация может обеспечить механизм для произвольные исходные файлы доступны для <> поиск, в общем программисты следует использовать форму <> для заголовков обеспечены реализацией, и "" форма для источников за пределами контроль реализации.

2 голосов
/ 28 января 2010

Я поддерживаю оба стиля ... для различного использования

Предположим, у вас также есть каталог root/src/common для моего примера

// in src/module1/foo.cpp
#include "module1/foo.h"

#include "../common/stringProcessing.h"

Включить

Я предпочитаю не видеть каталог 'include', поскольку, как сказано, конечно, найти точный заголовочный файл, таким образом, сложнее ... но когда вы начинаете и переходите к нескольким независимым библиотекам, вам НУЖНО абстрагироваться, потому что вы хотите быть в состоянии перемещать различные компоненты без изменения кода, и я все за последовательность.

Кроме того, всегда существует риск использования "..", что он не идет туда, куда вы думали, из-за символической ссылки, пройденной назад: /

Источник

Иногда у вас есть заголовки, которые не являются общедоступными и поэтому не находятся в каталоге include. Обычно это детали реализации, которые не имеют отношения к вашим клиентам. Я использую .., если необходимо, и уточняю точное местоположение.

Это позволяет: - не загромождать -I всеми возможными каталогами src - легко найти файл среди ваших источников - легко проверять зависимости между вашими источниками (grep для ..)

Разное

Если мне нужно набрать

#include "module/foo.h"

Тогда я ожидаю использовать:

module::Foo myClass;

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

Требуемая одна библиотека - одно пространство имен с одинаковыми именами облегчает навигацию по некоторым ~ 300 или ~ 400 компонентам, которые у нас есть: мы ДОЛЖНЫ разработать какой-то способ их организации!

Это означает, что ваш первоначальный макет был переработан как (для проекта module):

root
-- include
---- module
------ part1
------ part2
-- src
---- part1
---- part2

И тогда вы используете следующую директиву: -I/path../root/include И я ожидаю, что вы создадите либо libmodule.so библиотеку, либо module двоичный файл.

1 голос
/ 28 января 2010

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

Файлы могут перемещаться

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

Перемещение файлов без их изменения

Зная, что файлы будут перемещаться, если путь находится в файле, файл должен быть изменен при его перемещении. Без пути в файле нужно изменить только инструкции по сборке. В больших проектах изменение большого количества файлов является проблемой (даже при использовании сценариев).

На мой взгляд, пути в директивах #include являются злом. Люди, которые делают это, должны пройти переподготовку или отправлены в другие компании.

1 голос
/ 28 января 2010

В руководстве по стилю Google C ++ есть раздел , в котором обсуждаются порядок и наименования включений. Это в основном согласуется с тем, что было сказано в других ответах до сих пор, но стоит взглянуть, поскольку это очень специфично.

Я предпочитаю (и Google соглашается) не указывать относительные пути в директивах include. Ваша первоначальная оценка, что это выглядит аккуратно, правильна. Наличие длинных, неуклюжих относительных путей затрудняет чтение и рефакторинг. Я думаю, что ваш подход правильный.

Что касается разделения исходного кода и включения файлов в два разных поддерева: почему бы заголовкам не располагаться рядом с исходными файлами? Это облегчает сопоставление с ними. Я полагаю, если вы не ожидаете, что другие проекты будут использовать ваши заголовки и просто будут ссылаться на ваши двоичные файлы.
<Пожимание плечами />

1 голос
/ 28 января 2010

В качестве небольшого уточнения я предлагаю вам разрешить cc файлам в module1 напрямую обращаться к их .h файлам:

module1/%.cc: -I $ROOT/includes/module1

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

// module1/abc.cc
#include <abc.h>
#include <module2/def.h>
1 голос
/ 28 января 2010

У каждого стиля есть свои недостатки, но я предпочитаю тот, который вы указали. Путь включения не должен содержать восходящую относительность (например, ../..) и должен указывать модуль, на который он опирается.

1 голос
/ 28 января 2010

Я предпочитаю 2-й способ

#include <module1/foo.h>

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

...