2011-01-03 2 views
1

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

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

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

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

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

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

+1

Нет ничего синтаксически неправильного с помещением кода в заголовок, поэтому компилятор полностью прав, чтобы «разрешить» это. Либо одно из этих решений прекрасно. – Falmarri

+3

Использование fclose в коде C++ ВСЕГДА плохой стиль. – BatchyX

+10

@BatchyX: ВСЕ абсолютные осуждения ВСЕГДА ошибаются. –

ответ

2

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

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

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

+0

Да, и это может вызвать проблему, если в заголовке есть определение функции, потому что функция может быть определена в нескольких объектных файлах, а компоновщик не будет ссылаться и не будет подобным. – BatchyX

+1

Исправить. Функции, определенные в файлах заголовков, должны быть 'static' или' inline'. –

6

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

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

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

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

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

2

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

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

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

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

+1

Нет причин для статических встроенных линий - встроенные линии уже имеют внутреннюю связь. –

+0

Вы определенно нуждаетесь в этом 'static', если более одного блока компиляции содержит заголовок. Он должен быть встроен, но может и не быть. Используя подсказки ключевого слова 'inline' для компилятора, вы не думаете, что он должен добавлять дополнительные функции. Как отмечает @ Giuliano0, 'inline' не гарантирует, что он будет встроен. –

+1

Inline не может гарантировать встраивание кода, но он гарантирует внутреннюю связь, поэтому 'static' ничего не добавляет. –

0

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

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

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

3

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

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

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

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

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

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

+0

+1 для деталей на строках. –

+0

Хорошо указать, что разные компиляторы будут иметь разные способы принудительного ввода. Так что хорошо читать их документацию :) – Giuliano

Смежные вопросы