2010-11-04 1 views
9

Являются ли декларациями функций/прототипами в C99?Определить функцию перед основным?

В настоящее время я определяю свои функции в файле заголовка и # include-ING в главном файле. Это нормально в C99?

Почему большинство программистов объявляют/прорабатывают функцию перед main() и определяют ее после main()? Разве не проще определить их перед основным и избежать всех деклараций/прототипов?

Содержание header.h файла:

int foo(int foo) 
{ 
// code 
return 1; 
} 

Содержание основного файла:

#include <stdio.h> 

#include "header.h" 

int main(void) 
{ 
foo(1); 
return 0; 
} 

ответ

11

Как и где прототип и определить функцию в C:

  1. Ваша функция используется только в определенном файле .c: определить это статический в файле .c. Функция будет видна и скомпилирована для этого файла.

  2. Ваша функция используется в нескольких файлах .c: Выберите подходящий файл c для размещения вашего определения (например, все связанные с foo функции в файле foo.c) и связанный заголовочный файл, -статические (думают публичные) функции прототипированы. Функция будет скомпилирована только один раз, но видима для любого файла, который содержит файлы заголовков. Все будет собрано во время соединения. Возможное улучшение: всегда создавайте связанный файл заголовка, первый из которых включен в его c-файл, таким образом, вы будете уверены, что любой файл может включить его безопасно, без необходимости включения других, чтобы он работал, ссылка: Large Scale C++ projects (Большая часть правила применимы и к C).

  3. Ваша функция является inlinable (вы уверены, что это?): Определите функцию static inline в соответствующем файле заголовка. Компилятор должен заменить любой вызов вашей функции по определению, если это возможно (подумайте о макроподобности).

Понятие до-после другой функции (ваша основная функция) в c - это только вопрос стиля. Либо вы делаете:

static int foo(int foo) 
{ 
// code 
return 1; 
} 

int main(void) 
{ 
foo(1); 
return 0; 
} 

Или

static int foo(int foo); 

int main(void) 
{ 
foo(1); 
return 0; 
} 

static int foo(int foo) 
{ 
// code 
return 1; 
} 

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

+0

Могу ли я поставить декларацию 'static foo' в' .h' файл, определение в '.c' файле? – Alcott

+0

@Alcott: Нет, я думаю, вы получите ошибку: «foo» объявлен «статическим», но никогда не определялся »для каждого файла, который будет включать ваш заголовок. Подумайте о статическом как «локальном». Было бы нецелесообразно рекламировать (помещать в заголовочный файл) что-то как локальное для всех, если вы не предоставите его для локальной копии (вставки) всем. – Matthieu

1

Да, легче определить их перед основным. Если вы хотите использовать эти функции только внутри файла, прототип не нужен. Однако в этом случае вы также можете добавить ключевое слово «статическое» перед определением функции. (В файле C.) Это гарантирует, что функция не будет видна другим файлам. (При времени ссылки.)

Не ставьте статические ключевые слова во включенные файлы.

+0

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

+0

@Matthieu, хм, это не то, что я имел в виду. –

+1

@Matthieu: если вы используете классический стиль программирования C, статические функции вообще не должны появляться в заголовках. – kriss

4

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

+1

bang, как звук ошибки нескольких определений =) – Matthieu

+0

, но с помощью (смотреть) собаки и статические функции могут легко защитить вас от взрыва. Возможно, вы даже захотите определить функции в заголовках. Зачем вам это делать, звучать опасно (это так)? Большинство компиляторов лучше оптимизируют код статических функций. Стоимость - это время компиляции и дублирование кода, если вы не идете полностью (определите * все * программы в заголовках). В настоящее время я работаю над программой на C++ около 40000 строк, используя этот стиль, отлично подходит для меня. – kriss

3

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

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

+2

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

+0

@Matthieu: когда что-то хорошо, неясно, что делать точно противоположное тоже нехорошо. Как я уже сказал в ответе DeadMG, я определяю функции в заголовках, а не как привычку, а как трюк оптимизации и стиль программирования. Такая же идея, как «только заголовки» классов C++, сильно используемые BOOST. Вероятно, было бы бесполезно, если бы C или C++ имели чистую концепцию модулей, понимаемых компилятором (до привязки), как и другие языки, вместо этого кровавого уровня текста. – kriss

+0

@kriss: он может иметь смысл в C++, особенно с ограничениями шаблонов/метапрограмм (даже если вам нужно учитывать стоимость времени компиляции, как вы сказали), но я не вижу преимущества для определения заголовка в C, кроме как для inline , Я согласен с тем, что конструкция файла заголовка является «слабой точкой» для c/C++. – Matthieu

1

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

Обратите внимание, что в вашем примере вам следует избегать объявления foo() в файле заголовка: вы не сможете включить его в два разных исходных файла. Объявите его в файле C, содержащем main(); вам не нужно будет определять его в другом месте, если вы не ссылаетесь на него из других файлов.

0

Вы всегда должны быть прототипом.

Причины этого:

  1. методическим прототипирование производит краткий список в заголовочных файлах функций в коде - это неоценимое значение для будущих читателей

  2. ничего, кроме простейших проектов, многие функции не будут иметь видимость до начала основного ,

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

+0

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

+0

Когда я пишу библиотеки, в файлах C есть один H-файл, который является внутренним для библиотеки; который содержит прототипы (которые в противном случае были бы статическими, если бы все файлы C были свернуты в один). Он содержит список библиотечно-частных функций. Что касается файла, содержащего главную, я полностью согласен. – 2010-11-04 14:37:35

3

Вы должны всегда определять inline функции в заголовках. Хотя вы можете иметь функции extern inline, общим случаем является static inline.

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

  • объявления функций должны быть extern
  • определения функции должны быть static inline
  • объявления переменных должны быть extern
  • определения переменных должны быть static const

. Так как С. Росс попросил об этом, рассуждаем об этом: ресурс с внешней связью должен определяться только один раз [1]. Из этого следует, что определения не должны находиться в заголовочных файлах, которые предназначены для включения в несколько мест.

Определение static в заголовочных файлах не приведет к каким-либо проблемам, но, как правило, на него нахмурился, поскольку код должен быть скомпилирован более одного раза и будет присутствовать в разных объектных файлах, что увеличит размер исполняемого файла (при условии, что компоновщик недостаточно умен, чтобы разобраться в дублировании кода).

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

Примечание: [1] Это не относится к inline функций с внешним связыванием, но, как это определено, какие из многочисленных определений встроенной функции будет использоваться в оценке функции целеуказателем, они в основном бесполезны

+1

Правда, но вы не говорите * почему *. –

+0

Упрощенный, но все же у меня есть 2 вопроса. 1, Если я хочу использовать 'static void foo()' в программе, я должен помещать объявление 'foo' в файл' .h' программы или '.c' файл? Я задаю этот вопрос, потому что я смущен, если файлы '.h' содержат только' extern' функции, к которым могут обращаться несколько файлов '.c', а не только один? 2, я узнал, что функции 'inline' должны быть определены в' .h'-файлах, тогда зачем использовать 'static inline'? Значит ли 'static' означает, что встроенная функция будет видна только в одном файле' .c'? – Alcott

0

Почему большинство программистов объявляют/прорабатывают функцию перед main() и определяют ее после main()?

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

Конечно, если прототип кода находится в отдельном блоке компиляции, то необходимы прототипы :.

+0

Отныне я не буду считать себя полностью * человеком. :) –

4

Функция декларации требуются на C99. Функция прототипов не требуется на C99.

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

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

+1

+1 для «это никоим образом не то, что делают« большинство »программистов». –

0

Всегда полезно объявлять функции либо в главном, либо в отдельном файле заголовка, который будет включен в другие c-файлы, где мы использовали эту функцию. Делая это, мы можем легко идентифицировать все функции, объявленные/определенные в этих файлах .C или .H. И мы должны использовать ключевое слово extern перед объявлением функции в файле заголовка.