Стоит ли включать исходный код в заголовочный файл? - PullRequest
1 голос
/ 04 января 2011

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

Компилятор жалуется на то, что fclose () не объявлен в заголовочном файле.

здесь было объявление функции в заголовочном файле:

void closeFile() { if (fp) fclose(fp); }

Теперь я думаю, что это плохой стиль, но также - как они работали раньше?Разве их версия компилятора допускала такое поведение?

Должен ли я исправить это, включив stdio в заголовок, или перенести все это в cpp?

Ответы [ 5 ]

6 голосов
/ 04 января 2011

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

  • При определении класса / функции шаблона.

  • При определении встроенной функции.

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

Если вы получаете сообщение об ошибке, в котором говорится, что fclose не было объявлено, это, вероятно, потому что cstdio (или stdio.h) не был объявлен до этого куска кода.Поставьте #include <cstdio> в начале заголовочного файла.

3 голосов
/ 04 января 2011

Просто добавьте 2 вещи к другим ответам, помните, что inline - это не порядок, это скорее предположение о том, что должен делать компилятор, если только вы не заставите inline. Большинство компиляторов могут решить, когда встроить функцию, даже если вы не объявили ее встроенной. Это не должен , это должен .

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

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

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

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

Надеюсь, это поможет.

2 голосов
/ 04 января 2011

fclose() будет неопределенным, если вы не включили stdio.h ни в этот заголовок, ни перед тем, как его использовать везде.Вот почему возникает ошибка.

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

inline void closeFile() { if (fp) fclose(fp); }

Это означает, что несколько скомпилированных объектов не будут иметь closeFile() символов (из-за inline) и inline намекает компилятору, что его не следует оставлять как вызов функции, а подставлять inline что, вероятно, хотите, чтобы вы хотели для скорости.

2 голосов
/ 04 января 2011

Имейте в виду, что заголовочные файлы не компилируются сами по себе (обычно). Они #include d помещаются в исходные файлы, и определения, доступные при разборе файла заголовка, соответствуют тому, что было включено в исходный файл над рассматриваемым файлом заголовка.

Независимо от того, является ли файл заголовка подходящим местом для реализации closeFile(), ваш файл заголовка должен #include все, что ему нужно, наверху. Итак, добавьте #include <stdio.h> вверху заголовочного файла.

(Обратите внимание: если это код, предназначенный для компиляции в само ядро ​​Linux, вам может потребоваться заголовок, отличный от stdio.h. Часто заголовки уровня приложения не подходят для использования в исходных кодах ядра.)

0 голосов
/ 04 января 2011

Заголовки включаются текстовыми подстановками (то есть все содержимое заголовка подставляется в объявление #include).Таким образом, если существует только один файл .cpp, который включает этот конкретный заголовок, это эквивалентно определению функции в файле .cpp.Я думаю, что это причина, по которой он работал (во время соединения).

Стандарт C определяет только заголовок, который должен быть включен, чтобы иметь доступную функцию, но не запрещает системному заголовку включать друг друга.Таким образом, возможно, что в некоторой системе заголовок stdio.h был неявно включен другим заголовком (и, следовательно, компилятор не сообщал об ошибке).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...