Должен ли прототип функции всегда находиться в заголовочном файле?

Допустим, у нас есть несколько исходных файлов C, таких как file1.c, file2.c и main.c. У нас есть функции как:

file1.c
      |---> file1Func1()
      |---> file1Func2()

file2.c
      |---> file2Func1()
      |---> file2Func2()

и основной файл использует эти функции. Теперь было бы естественно создать и добавить соответствующий прототип функции в файлы заголовков file1.h и file2.h, а затем включить эти заголовки в main.c для использования функций.

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

Или использовать extern для использования функции, определенной в другом месте (в другом исходном файле), и полагаться на компоновщик для поиска и извлечения функции из объектного файла во время компоновки?

Примечание: при использовании последнего подхода MISRA выдает предупреждение об отсутствии прототипа функции.


person Osaid    schedule 18.03.2016    source источник


Ответы (3)


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

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

Так пишутся все (профессиональные) программы на C. В качестве примечания, этот звуковой дизайн также требуется для MISRA-C.

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

void func (void);

полностью эквивалентен

extern void func (void);

Если вам нужно использовать функцию, включите соответствующий заголовок.

person Lundin    schedule 18.03.2016
comment
Хотя я согласен с вами по поводу эквивалентности, я предпочитаю видеть ключевое слово extern, поскольку оно явно показывает глобальный характер. Имейте в виду, я предпочитаю терминологию общедоступного/частного С++, а не внешний/статический. - person Andrew; 05.07.2016
comment
@ Эндрю Это в основном вопрос стиля. Кому-то нравится быть откровенным, кто-то считает это излишним. Однако в будущих инструкциях по языку C11 говорится, что объявление идентификатора с внутренней связью в области файла без спецификатора статического класса хранения является устаревшей функцией. Поэтому я предполагаю, что в будущих стандартах C мы не сможем объявлять функции без использования extern. Я очень сомневаюсь, что комитет осмелится пойти на этот шаг, так как это нарушит так много существующего кода. Я думаю, что причина здесь в том, чтобы запретить такие идентификаторы типа объекта, то есть: глобальные. - person Lundin; 05.07.2016
comment
В самом деле... и есть более важные вещи, которые нужно исправить, несмотря на одержимость WG14 обратной совместимостью! - person Andrew; 12.07.2016

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

Краткий ответ - да".

Немного более длинный ответ: «Да, но вы можете опустить функции из файлов заголовков, которые являются деталями реализации других функций в исходном файле».

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

person R Sahu    schedule 18.03.2016

должен ли я всегда создавать заголовок (затем добавлять прототип функции) для каждого исходного файла.

Ответ TL;DR; — Да.

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

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

Все глобальные объекты (включая прототипы функций) должны быть объявлены в заголовочном файле; Я также выступаю за то, чтобы ключевое слово extern никогда (*) не использовалось в исходном файле C, поскольку это (ИМХО) нарушает заявленный интерфейс для модуля.

{*} Хорошо, никогда не является сильным словом, и могут быть исключения... но их должно быть немного и далеко друг от друга.

person Andrew    schedule 05.07.2016