c / c ++ включает порядок заголовочных файлов

<p>в каком порядке должны быть указаны файлы, т. е. каковы причины включения одного заголовка перед другим?</p><p>например, системные файлы, stl и boost идут до или после локальных включаемых файлов?</p>

<p>я не думаю, что есть рекомендуемый порядок, пока он компилируется! что раздражает, так это то, что некоторые заголовки требуют, чтобы другие заголовки включались первыми ... это проблема самих заголовков, а не порядка включений.</p><p>мое личное предпочтение состоит в том, чтобы перейти от локального к глобальному, каждый подраздел в алфавитном порядке, т.е.</p><ol> <li>h-файл, соответствующий этому cpp-файлу (если применимо)</li> <li>заголовки из того же компонента,</li> <li>заголовки из других компонентов,</li> <li>системные заголовки.</li> </ol><p>мое обоснование для 1. состоит в том, что он должен доказать, что каждый заголовок (для которого есть cpp) может быть <code>#include</code>d без предварительных условий. а все остальное кажется логически вытекающим оттуда.</p>

<p>важно помнить, что ваши заголовки не должны зависеть от других заголовков, включаемых в первую очередь. один из способов обеспечить это - включить заголовки перед любыми другими заголовками.</p><p>в частности, это упоминается в статье "мышление в c++", ссылаясь на "крупномасштабное проектирование программного обеспечения c++" лакоса:</p><blockquote>скрытых ошибок использования можно избежать, если обеспечить, чтобы файл .h компонента анализировался сам по себе - без предоставленных извне объявлений или определений ... включение файла .h в качестве самой первой строки файла .c гарантирует, что никакой критической части не будет информация, присущая физическому интерфейсу компонента, отсутствует в файле .h (или, если таковой имеется, вы узнаете об этом, как только попытаетесь скомпилировать файл .c).</blockquote><p>то есть включить в следующем порядке:</p><ol> <li>заголовок прототипа/интерфейса для этой реализации (т. е. файл .h/.hh, соответствующий этому файлу .cpp/.cc).</li> <li>другие заголовки из того же проекта, по мере необходимости.</li> <li>заголовки из других нестандартных, несистемных библиотек (например, qt, eigen и т.д.).</li> <li>заголовки из других "почти стандартных" библиотек (например, boost)</li> <li>стандартные заголовки c++ (например, iostream, функционал и т.д.)</li> <li>стандартные заголовки c (например, cstdint, dirent.h и т.д.)</li> </ol><p>если у какого-либо из заголовков есть проблема с включением в этот порядок, либо исправьте их (если они у вас есть), либо не используйте их. бойкот библиотеки, которые не пишут чистые заголовки.</p><p> <a href="https://google.github.io/styleguide/cppguide.html#names\_and\_order\_of\_includes">руководство по стилю google c++</a> утверждает <i>почти</i> наоборот, безо всякого оправдания; я лично склоняюсь в пользу подхода лакоса.</p>

<p>я следую двум простым правилам, которые избегают подавляющего большинства проблем:</p><ol> <li>все заголовки (и действительно <em>любые</em> исходные файлы) должны включать то, что им нужно. они должны <em>не</em> полагаться на своих пользователей, включая вещи.</li> <li>в качестве дополнения, все заголовки должны иметь охранников, чтобы они не включались несколько раз из-за чрезмерно амбициозного применения правила 1 выше.</li> </ol><p>я также следую инструкциям:</p><ol> <li>сначала включите системные заголовки (stdio.h и т.д.) с разделительной линией.</li> <li>группируйте их логически.</li> </ol><p>другими словами:</p><pre><code>#include <stdio.h> #include <string.h> #include "btree.h" #include "collect\_hash.h" #include "collect\_arraylist.h" #include "globals.h" </code></pre><p>хотя, будучи руководством, это субъективная вещь. с другой стороны, я строго соблюдаю правила, вплоть до предоставления заголовочных файлов "обертки" с включенными защитами и сгруппированными включениями, если какой-то неприятный сторонний разработчик не подпишется на мое видение :-)</p>

<p>чтобы добавить мой собственный кирпич к стене.</p><ol> <li>каждый заголовок должен быть самодостаточным, который можно проверить, только если он включен хотя бы один раз</li> <li>не следует ошибочно изменять значение стороннего заголовка, вводя символы (макро, типы и т.д.)</li> </ol><p>так что я обычно так:</p><pre><code>// myproject/src/example.cpp #include "myproject/example.h" #include <algorithm> #include <set> #include <vector> #include <3rdparty/foo.h> #include <3rdparty/bar.h> #include "myproject/another.h" #include "myproject/specific/bla.h" #include "detail/impl.h" </code></pre><p>каждая группа отделена пустой строкой от следующей:</p><ul> <li>заголовок, соответствующий этому файлу cpp первым (проверка работоспособности)</li> <li>системные заголовки</li> <li>сторонние заголовки, организованные по порядку зависимости</li> <li>заголовки проекта</li> <li>частные заголовки проекта</li> </ul><p>также обратите внимание, что помимо системных заголовков каждый файл находится в папке с именем своего пространства имен, просто потому, что его легче отследить таким образом.</p>

<p>я почти уверен, что это не рекомендуемая практика нигде в нормальном мире, но мне нравится, когда система включает в себя длину файла, отсортированную по лексике в той же длине. вот так:</p><pre><code>#include <set> #include <vector> #include <algorithm> #include <functional> </code></pre><p>я думаю, что это хорошая идея, чтобы включить свои собственные заголовки перед другими народами, чтобы избежать позора зависимости порядка включения.</p>

<p>рекомендую:</p><ol> <li>заголовок для создаваемого вами модуля .cc. (помогает убедиться, что каждый заголовок в вашем проекте не имеет неявных зависимостей от других заголовков в вашем проекте.)</li> <li>c системные файлы.</li> <li>c++ системные файлы.</li> <li>платформа/os/другие файлы заголовков (например, win32, gtk, opengl).</li> <li>другие заголовочные файлы из вашего проекта.</li> </ol><p>и, конечно же, алфавитный порядок в каждом разделе, где это возможно.</p><p>всегда используйте предварительные объявления, чтобы избежать ненужных <code>#include</code>s в заголовочных файлах.</p>

<p>это не субъективно. убедитесь, что ваши заголовки не зависят от <code>#include</code>d в определенном порядке. вы можете быть уверены, что не имеет значения, в каком порядке вы включаете заголовки stl или boost.</p>

<p>сначала включите заголовок, соответствующий .cpp ... другими словами, <code>source1.cpp</code> должен включать <code>source1.h</code>, прежде чем включать что-либо еще. единственное исключение, о котором я могу подумать, - это использование msvc с предварительно скомпилированными заголовками. в этом случае вы должны включить <code>stdafx.h</code> прежде всего.</p><p><strong>reasoning:</strong> включение <code>source1.h</code> перед любыми другими файлами гарантирует, что он может работать самостоятельно без своих зависимостей. если <code>source1.h</code> получит зависимость в более позднюю дату, компилятор немедленно предупредит вас о необходимости добавить необходимые предварительные объявления в <code>source1.h</code>. это, в свою очередь, гарантирует, что заголовки могут быть включены в любом порядке их зависимыми.</p><p>пример:</p><p><strong>source1.h</strong></p><pre><code>class class1 { class2 c2; // a dependency which has not been forward declared }; </code></pre><p><strong>source1.cpp</strong></p><pre><code>#include "source1.h" // now compiler will alert you saying that class2 is undefined // so you can forward declare class2 within source1.h ... </code></pre><p><strong>пользователи msvc:</strong> я настоятельно рекомендую использовать предварительно скомпилированные заголовки. итак, переместите все директивы <code>#include</code> для стандартных заголовков (и других заголовков, которые никогда не изменятся) в <code>stdafx.h</code>.</p>

<p>включите от наиболее конкретного к наименее конкретному, начиная с соответствующего .hpp для .cpp, если таковой существует. таким образом, будут обнаружены любые скрытые зависимости в заголовочных файлах, которые не являются самодостаточными.</p><p>это осложняется использованием предварительно скомпилированных заголовков. одним из способов обойти это, не делая ваш проект специфичным для компилятора, является использование одного из заголовков проекта в качестве файла скомпилированного заголовка.</p>

<p>это сложный вопрос в мире c/c++, с таким количеством элементов, выходящих за рамки стандарта.</p><p>я думаю, что порядок заголовочных файлов не является серьезной проблемой, пока он компилируется, как сказал squelart.</p><p>мои идеи таковы: если во всех этих заголовках нет конфликта символов, любой порядок в порядке, и проблему с зависимостью заголовка можно исправить позже, добавив строки #include в некорректный .h.</p><p>настоящая проблема возникает, когда какой-то заголовок меняет свое действие (проверяя условия #if) в соответствии с тем, какие заголовки указаны выше.</p><p>например, в stddef.h в vs2005 есть:</p><pre><code>#ifdef \_win64 #define offsetof(s,m) (size\_t)( (ptrdiff\_t)&(((s *)0)->m) ) #else #define offsetof(s,m) (size\_t)&(((s *)0)->m) #endif </code></pre><p>теперь проблема: если у меня есть собственный заголовок ("custom.h"), который нужно использовать со многими компиляторами, включая некоторые старые, которые не предоставляют <code>offsetof</code> в своих системных заголовках, я должен написать в своем заголовке:</p><pre><code>#ifndef offsetof #define offsetof(s,m) (size\_t)&(((s *)0)->m) #endif </code></pre><p>и обязательно сообщите пользователю <code>#include "custom.h"</code> <strong>после</strong> всех системных заголовков, в противном случае строка <code>offsetof</code> в stddef.h выдаст ошибку переопределения макроса.</p><p>мы молимся, чтобы больше не встречаться с такими случаями в нашей карьере.</p>