Некоторые программы построены таким образом.
Типичный пример: SQLite. Он иногда компилируется как amalgamation (выполняется во время сборки из многих исходных файлов).
Но этот подход имеет свои плюсы и минусы.
Очевидно, что время компиляции увеличится довольно много. Так что это практично, только если вы собираете этот материал редко.
Возможно, компилятор может немного оптимизировать. Но с оптимизацией времени соединения (например, при использовании последнего GCC, компиляции и связи с gcc -flto -O2
) вы можете получить тот же эффект (конечно, за счет увеличения времени сборки).
Я не должен написать файл заголовка для каждой функции
Это неправильный подход (чтобы иметь один файл заголовка каждой функции).Для проекта с одним человеком (менее ста тысяч строк кода, например, KLOC = кило-линия code), вполне разумно - по крайней мере, для небольших проектов - иметь общий заголовочный файл (4415) pre-compile при использовании GCC), в котором будут содержаться декларации всех публичных функций и типов и, возможно, определения из static inline
функций (достаточно маленьких и достаточно часто вызываемых, чтобы получить прибыль от inlining). Например, sash
shell организован таким образом (а также lout
formatter, с 52 KLOC).
Возможно, у вас также есть несколько файлов заголовков и, возможно, есть отдельный заголовок «группировки», который все они (и которые вы можете предварительно скомпилировать). Смотрите, например jansson (который на самом деле имеет один общественного заголовка файла) и GTK (который имеет много внутренних заголовков, но большинство приложений, использующих его have только один #include <gtk/gtk.h>
, который, в свою очередь, включают все внутренние заголовки). На противоположной стороне POSIX имеет большое количество файлов заголовков, и он документирует, какие из них должны быть включены и в каком порядке.
Некоторые люди предпочитают иметь много файлов заголовков (а некоторые даже предпочитают помещать объявление одной функции в свой собственный заголовок). Я не делаю (для личных проектов или небольших проектов, на которых только два или три человека совершают кодекс), но это вопрос вкус. Кстати, когда проект много растет, часто случается, что набор файлов заголовков (и единиц перевода) значительно меняется. Посмотрите также на REDIS (у него есть 139 .h
файлы заголовков и 21 файлов, т. Е. Единицы перевода, суммирующие 126 KLOC).
Наличие одного или нескольких translation units также является вопросом вкуса (и удобства и привычек и условностей). Мое предпочтение состоит в том, чтобы иметь исходные файлы (то есть единицы перевода), которые не слишком малы, обычно несколько тысяч строк каждый, и часто имеют (для небольшого проекта менее 60 KLOC) общий одиночный заголовочный файл. Не забудьте использовать какой-нибудь инструмент build automation, например GNU make (часто с parallel, через make -j
, тогда у вас будет несколько процессов компиляции, выполняющихся одновременно). Преимущество такой организации исходного файла заключается в том, что компиляция достаточно быстро. BTW, в некоторых случаях стоит подход metaprogramming: некоторые из ваших (внутренних заголовков или единиц перевода) C «исходные» файлы могут быть сгенерированы чем-то другим (например, какой-то скрипт в AWK, некоторые специализированные программы на C, такие как bison или ваш собственная вещь).
Помните, что C был спроектирован в 1970-х годах, для компьютеров, которые намного меньше и медленнее, чем ваш любимый ноутбук сегодня (как правило, в то время в памяти было не более мегабайта или даже несколько сотен килобайт, а компьютер был как минимум в тысячу раз медленнее, чем ваш мобильный телефон сегодня).
я настоятельно рекомендую изучить исходный код и создать некоторые существующихfree software проектов (например, те, на GitHub или SourceForge или ваш любимом дистрибутиве Linux). Вы узнаете, что они разные подходы.Помните, что в C конвенции и привычки материи много на практике, так есть различные способов организовать свой проект в .c
и .h
файлов. Читайте о C preprocessor.
Это также означает, что я не должен включать стандартные библиотеки в каждом файле я создаю
Включаешь заголовочные файлы, а не библиотеки (но вы должны link библиотеки). Но вы можете включить их в каждый файл .c
(и это делают многие проекты), или вы можете включить их в один заголовок и предварительно скомпилировать этот заголовок, или у вас может быть дюжина заголовков и включать их после заголовков системы в каждом сбор единица измерения. YMMV. Обратите внимание, что на современных компьютерах быстро выполняется предварительная обработка (по крайней мере, когда вы просите компилятор оптимизировать, поскольку оптимизация занимает больше времени, чем обработка & предварительной обработки).
Обратите внимание, что в какой-то #include
-d файл находится обычный (и не определяется спецификацией C). Некоторые программы имеют некоторый код в каком-то таком файле (который затем не следует называть «заголовком», просто «включенным файлом», и который тогда не должен иметь суффикса .h
, но что-то вроде .inc
). Посмотрите пример на XPM. С другой стороны, вы, возможно, в принципе не имеете никаких собственных файлов заголовков (вам все равно нужны файлы заголовков из реализации, например <stdio.h>
или <dlfcn.h>
из вашей системы POSIX), а также скопируйте и вставьте дублированный код в файлы .c
-e.g. имеют строку int foo(void);
в каждом файле .c
, но это очень плохая практика и нахмурился. Тем не менее, некоторые программы - это , генерирующие файлы C, в которых используется общий контент.
BTW, C или C++ 14 не имеют модулей (например, OCaml). Другими словами, в модуле C в основном используется соглашение .
(обратите внимание, что наличие многих тысяч очень маленьких.h
и .c
файлов всего лишь нескольких десятков строк каждый может замедлить время сборки драматический, имея сотню файлов в нескольких сот линий, каждый является более разумным, в срок строительства.)
Если вы начнете работать над проектом с одним человеком в C, я бы предложил сначала иметь один заголовочный файл (и предварительно скомпилировать его) и несколько блоков перевода .c
. На практике вы измените файлы .c
гораздо чаще, чем .h
. Если у вас более 10 KLOC, вы можете реорганизовать это в несколько файлов заголовков. Такой рефакторинг сложный для проектирования, но его легко сделать (просто копия &, вставляющая кусок кодов). У других людей были бы разные предложения и подсказки (и это нормально!). Но не забудьте включить все предупреждения и отладочную информацию при компиляции (поэтому компилируйте с помощью gcc -Wall -g
, возможно, установив CFLAGS= -Wall -g
в свой Makefile
). Используйте отладчик gdb
(и valgrind ...). Попросите оптимизацию (-O2
), когда вы сравниваете уже отлаженную программу. Также используйте систему управления версиями, например Git.
Напротив, если вы проектируете более крупный проект, на котором будет работать , будет работать несколько человек, было бы лучше иметь несколько файлов - даже несколько файлов заголовков - (интуитивно, каждый файл имеет одного человека, несущего основную ответственность за он, а другие делают незначительный вклад в этот файл).
В комментарии, добавьте:
Я говорю о написании моего кода в большом количестве различных файлов, но с помощью Makefile, чтобы сцепить их
Я не вижу, почему это было бы полезно (за исключением очень странных случаев). Гораздо лучше (и очень обычная и обычная практика) собрать каждую блок перевода (например, каждый файл .c
) в его object file (файл .o
ELF на Linux) и link их позже. Это легко с make
(на практике, когда вы измените только один файл .c
, например, чтобы исправить ошибку, только этот файл компилируется, а инкрементная сборка очень быстрая), и вы можете попросить его скомпилировать объектные файлы в parallel, используя make -j
(а затем ваша сборка идет очень быстро на вашем многоядерном процессоре).
Ваш пример неправильный: прототип необходим для 'foo'. – LPs
Читайте о передовых декларациях, и вы поймете, что не так, имея только один .c файл. А также это будет сумасшедший беспорядок. –
C - это не один из современных языков, где символы могут быть определены только * где-то * в контексте проекта. Он имеет очень строгие правила в отношении областей видимости и разрешения. Используйте другой язык, если вы хотите область проекта для именованных идентификаторов. – grek40