Лучше ли документировать функции в заголовочном файле или исходном файле?

86

На языках, которые различают исходный файл и файл заголовка (в основном C и C ++), лучше документировать функции в заголовочном файле:

(ворованный из CCAN )

/**
 * time_now - return the current time
 *
 * Example:
 *  printf("Now is %lu seconds since epoch\n", (long)time_now().tv_sec);
 */
struct timeval time_now(void);

или в исходном файле?

(украдено из PostgreSQL)

/*
 * Convert a UTF-8 character to a Unicode code point.
 * This is a one-character version of pg_utf2wchar_with_len.
 *
 * No error checks here, c must point to a long-enough string.
 */
pg_wchar
utf8_to_unicode(const unsigned char *c)
{
...

Обратите внимание, что некоторые вещи определены только в заголовке, например структуры, макросы и static inlineфункции. Я говорю только о вещах, которые объявлены в заголовочном файле и определены в исходном файле.

Вот некоторые аргументы, которые я могу придумать. Я склоняюсь к документированию в исходном файле, поэтому мои аргументы «Pro-header» могут быть несколько слабыми.

Pro-заголовок:

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

Pro-источник:

  • Это делает заголовок намного короче, предоставляя читателю обзор модуля в целом.
  • Он сопрягает документацию функции с ее реализацией, облегчая понимание того, что функция делает то, что говорит.

При ответе, пожалуйста, будьте осторожны с аргументами, основанными на том, что могут сделать инструменты и «современные IDE». Примеры:

  • Pro-header: свертывание кода может помочь сделать заголовки с комментариями более удобными, скрывая комментарии.
  • Pro-источник: Cscope «s Find this global definitionфункция принимает вас к исходному файлу (где определение является) , а не файл заголовка (где декларация является).

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

Джои Адамс
источник
Тот же вопрос применим к Pascal / Delphi, где у нас нет исходных и заголовочных файлов, но есть разделы интерфейса и реализации.
Ян Догген
1
См. Также stackoverflow.com/questions/355619/…
cp.engr

Ответы:

96

Мой вид...

  • Документ о том, как использовать функцию в заголовочном файле или, точнее, близко к объявлению.

  • Документируйте, как работает функция (если это не очевидно из кода) в исходном файле или, точнее, близко к определению.

Для того, чтобы с высоты птичьего полета в заголовке вам не обязательно закрывать документацию - вы можете сразу задокументировать группы объявлений.

Вообще говоря, вызывающая сторона должна интересоваться ошибками и исключениями (если только они могут быть переведены, поскольку они распространяются через уровни абстракции), поэтому они должны быть задокументированы рядом с соответствующими объявлениями.

Steve314
источник
13
+1 - т.е. документировать интерфейс в шапке. Горы подробно рассказывают как и почему в источнике.
быстро,
2
Для заголовков библиотек, где нет доступного источника, можно добавить предварительные и последующие условия и т. Д., Чтобы помочь с тестированием. Плюс добавьте O (n) производительности, если это имеет смысл, чтобы пользователи библиотеки могли выбирать мудро.
Патрик Хьюз
Естественно, иногда декларация и определение - это одно и то же.
Дедупликатор
@Deduplicator - когда одни и те же правила приводят к правильным вещам даже в особом случае, зачем повторять эти правила для каждого особого случая? Конечно, дедупликатор не должен этого хотеть?
Steve314
1
@Deduplicator - конечно, это разумное обоснование для того, чтобы не следовать вашему совету, но я придерживаюсь его.
Steve314
34

Если вы собираетесь использовать такой инструмент, как Doxygen (обратите внимание, в первом примере, который действительно выглядит как комментарий Doxygen, потому что он начинается с /**), тогда это не имеет значения - Doxygen будет просматривать заголовок и исходные файлы и находить все комментарии для генерации документации.

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

Если вы посмотрите на большинство библиотек Linux, например, ваша система управления пакетами Linux часто имеет пакет, который содержит только двоичные файлы библиотеки (для «обычных» пользователей, у которых есть программы, которым нужна библиотека), и у вас есть пакет «dev», который содержит заголовки для библиотеки. Исходный код обычно не поставляется напрямую в пакете. Было бы очень обременительно, если бы вам нужно было где-нибудь получить исходный код библиотеки, чтобы получить документацию по API.

Jesper
источник
2
+1 - при условии, что даже если вы используете Doxygen, это не значит, что вы никогда не будете читать напрямую из источника. Аннотации Doxygen даже иногда полезны как стандартные шаблоны для поиска, и это удобно, если найденная вами аннотация близка к коду, который она описывает.
Steve314
1
@ Steve314 Конечно, я не говорил, что вы никогда не захотите взглянуть на исходный код какой-либо библиотеки - но это не первое место, где вы будете искать, как выглядит API и как его использовать.
Джеспер
Я также рекомендовал бы хранить все, что связано с API, в заголовке (или, по крайней мере, либо в заголовке, либо в источнике), поскольку это позволит избежать потенциальной несогласованности при обновлении документации в одном месте, а не в другом.
Jopasserat
12

Мы решили эту проблему (около 25 лет назад), создав кучу #defines (например, public, private и т. Д., Которые были преобразованы в <nothing>), которые могли бы использоваться в исходном файле и сканироваться скриптом awk (ужасы). !) для автоматической генерации .h файлов. Это означает, что все комментарии жили в источнике и были скопированы (при необходимости) в сгенерированный файл .h. Я знаю, что это довольно старая школа, но она значительно упростила этот вид встроенной документации.

Питер Роуэлл
источник
1
хм, я знаю, что этот стиль вещей может быть полезен, но с моей точки зрения я всегда находил, что такая документация прямо раздражает ...
osirisgothra
1
Перефразируя Дональда Рамсфелда (человека, которого я не любил): «Вы программируете с помощью инструментов, которые у вас есть, а не с инструментами, которые вы хотели бы иметь». На каждом языке, с которым я работал за последние 40 с лишним лет, была как минимум одна крупная бородавка (если не больше). Наше решение а) сработало, б) использовало инструменты, которые существовали в то время, в) позволило нам потратить время на получение кода, приносящего доход.
Питер Роуэлл
Хотя я, вероятно, не выбрал бы это, это интересный способ обработки комментариев в заголовках. Будут ли сгенерированные заголовки в управлении версиями? или это какой-то процесс релиза для создания распространяемого источника? (но не используется разработчиками)
ideasman42
О, я недавно видел ту же модель в проекте, начатом в 2000 году, и они так гордились своим умным изобретением ...
5gon12eder
3
В нашем случае мы не держали ни один из сгенерированных файлов под контролем версий, поскольку они были легко и непосредственно (повторно) получены из отслеживаемых файлов.
Питер Роуэлл
9

Предполагая, что это код в более крупном проекте (где разработчики будут часто перемещаться между источником и заголовками) , и если это не библиотека / промежуточное ПО, где другие могут не иметь доступа к источнику, я нашел, что это работает Лучший...

  • Заголовки:
    краткие 1-2-строчные комментарии, только если они необходимы.
    Иногда полезны также комментарии над группой связанных функций.
  • Источник:
    Документация по API непосредственно над функцией (простой текст или doxygen, если вы предпочитаете) .
  • Сохраняйте детали реализации, относящиеся только к разработчику, изменяющему код в теле функции.

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

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


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

ideasman42
источник
5

По моему (довольно ограниченному и предвзятому) мнению, я являюсь образцом мышления на основе исходного кода. Когда я делаю кусочки в C ++, я обычно редактирую заголовочный файл один раз, а потом никогда не возвращаюсь к нему.

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

Но это только я ...

MattyD
источник
1
Не очень хорошо работает, если у вас есть только скомпилированная библиотека и файл заголовка. В этом случае больше информации в заголовке - это хорошо, потому что это единственная документация по интерфейсу, которая у вас есть.
quick_now
вы можете сгенерировать документацию с помощью doxygen - он также берет ее из файлов .c. Таким образом, вы можете легко распространять документацию с помощью скомпилированных библиотек. Но проблема заключалась бы в IDE, которая может анализировать заголовочные файлы и предоставлять вам документацию при использовании функции ... Но, возможно, она могла бы решить некоторый сценарий развертывания, который бы копировал комментарии функции frm .c в .h ...
Вит Бернатик
5

Комментарии не являются документацией. Документация для функции обычно может составлять 2 КБ текста, возможно, с диаграммами - см., Например, документацию для функций в Windows SDK. Даже если ваш комментарий к документу допускает такую ​​вещь, вы сделаете код, содержащий комментарий, нечитаемым. Если вы хотите производить документацию, используйте текстовый процессор.

Нил Баттерворт
источник
обновите, в наши дни намного проще документировать (с помощью таких вещей, как Qt creator), чтобы просто документировать doxygen (или клонировать), например, в qtc вы просто нажимаете клавишу / несколько раз перед комментарием и половину работа сделана для вас. Из-за таких вещей, я сомневаюсь, что люди захотят перейти к текстовому процессору, чтобы просто документировать свой код. Я имел обыкновение делать это, конечно, еще в 2005 году, но я бы никогда не сделал этого сейчас. Даже использование html-редактора кажется довольно архаичным.
osirisgothra
@osirisgothra Doxygen- «документация» может быть легко сделать, и , конечно , производит много быстро написанные оргкомитеты, но стоимость производства «документации» остается спорной в подавляющем большинстве случаев. Комментарии Doxygen не являются ни хорошей документацией (почти все важные детали обычно отсутствуют), ни хорошими комментариями (они имеют тенденцию повторять то, что уже очевидно из подписи). Я думаю, что nbt прав, говоря, что настоящая документация лучше не смешивать с кодом, потому что это наносит ущерб читабельности кода. В любом случае, это не будет синхронизировано, для этого нет серебряной пули.
cmaster
4

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

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

rwong
источник
0

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

Slava
источник
1
это , кажется, не предлагает ничего существенного над точкой сделана и объяснена в предшествующем уровне 7 ответов
комар
1
@gnat из предыдущих 7 ответов только один выступает за код против заголовков. И тот дает совершенно другую аргументацию.
Слава