2016-03-18 10 views
1

Допустим, у нас есть несколько исходных файлов C, таких как file1.c, file2.c и main.c. У нас есть следующие функции:Должен ли прототип функции всегда находиться в файле заголовка?

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

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

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

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

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

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

ответ

1

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

Короткий ответ «Да».

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

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

4

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

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

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

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

void func (void); 

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

extern void func (void); 

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

+0

Хотя я согласен с вами относительно эквивалентности, я предпочитаю видеть ключевое слово 'extern', поскольку это явно показывает глобальную природу. Имейте в виду, я предпочитаю терминологию C++ публичного/частного над extern/static – Andrew

+1

@Andrew Это в основном вопрос стиля. Некоторым нравится быть явным, некоторые считают, что это лишнее. Однако в будущих языках языка C11 говорится, что «объявление идентификатора с внутренней связью в области файлов без статического класса хранения спецификатор является устаревшей функцией». Поэтому я предполагаю, что в будущих стандартах C мы не сможем объявлять функции без использования extern. Я очень сомневаюсь, что комитет посмеет принять этот шаг, хотя, так как он сломает так много существующего кода. Я думаю, что здесь обоснование состоит в том, чтобы запретить такие идентификаторы типа объекта, то есть: «глобальные». – Lundin

+0

Действительно ... и есть более важные вещи, которые нужно исправить, несмотря на одержимость WG14 с обратной совместимостью! – Andrew

0

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

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

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

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

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

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