Например, инструмент SysInternals "FileMon" из прошлого имеет драйвер режима ядра, исходный код которого полностью находится в одном файле из 4000 строк. То же самое для первой когда-либо написанной программы ping (~ 2000 LOC).
Например, инструмент SysInternals "FileMon" из прошлого имеет драйвер режима ядра, исходный код которого полностью находится в одном файле из 4000 строк. То же самое для первой когда-либо написанной программы ping (~ 2000 LOC).
Ответы:
Использование нескольких файлов всегда требует дополнительных административных затрат. Нужно настроить скрипт сборки и / или make-файл с отдельными этапами компиляции и компоновки, убедиться, что зависимости между различными файлами корректно управляются, написать скрипт «zip» для более легкого распространения исходного кода по электронной почте или загрузке и т. Д. на. Современные IDE сегодня обычно берут на себя это бремя, но я уверен, что в то время, когда была написана первая программа ping, такой IDE не было. А для файлов размером ~ 4000 LOC без такой IDE, которая хорошо управляет несколькими файлами, компромисс между упомянутыми издержками и преимуществами использования нескольких файлов может позволить людям принять решение о подходе с одним файлом.
Потому что C не хорош в модульности. Он запутывается (файлы заголовков и #include, функции extern, ошибки во время компоновки и т. Д.), И чем больше модулей вы вводите, тем сложнее становится.
Более современные языки имеют лучшие возможности модульности отчасти потому, что они учились на ошибках С, и они облегчают разбивку вашей кодовой базы на более мелкие и простые модули. Но с C может быть полезно избежать или минимизировать все эти проблемы, даже если это означает объединение того, что в противном случае считалось бы слишком большим количеством кода в одном файле.
Помимо исторических причин, есть одна причина использовать это в современном чувствительном к производительности программном обеспечении. Когда весь код находится в одном модуле компиляции, компилятор может выполнять оптимизацию всей программы. С отдельными модулями компиляции компилятор не может оптимизировать всю программу определенными способами (например, вставляя определенный код).
Компоновщик, безусловно, может выполнять некоторые оптимизации в дополнение к тому, что может делать компилятор, но не все. Например: современные компоновщики действительно хороши для исключения функций, на которые нет ссылок, даже для нескольких объектных файлов. Они могут быть в состоянии выполнить некоторые другие оптимизации, но ничего общего с тем, что компилятор может делать внутри функции.
Одним из хорошо известных примеров модуля с одним исходным кодом является SQLite. Вы можете прочитать больше об этом на странице объединения SQLite .
1. Резюме
Более 100 отдельных исходных файлов объединяются в один большой файл C-кода с именем «sqlite3.c» и называются «объединением». Объединение содержит все, что необходимо приложению для встраивания SQLite. Файл объединения имеет длину более 180 000 строк и размер более 6 мегабайт.
Объединение всего кода для SQLite в один большой файл упрощает развертывание SQLite - существует только один файл для отслеживания. А поскольку весь код находится в одном модуле перевода, компиляторы могут лучше оптимизировать межпроцедурную оптимизацию, в результате чего машинный код работает на 5-10% быстрее.
$(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) $(CFILES)
чем перенести все в один файл соудс. Вы даже можете выполнить компиляцию всей программы в качестве альтернативы целевому сценарию, который пропускает перекомпиляцию исходных файлов, которые не изменились, подобно тому, как люди могут отключить профилирование и отладку для производственной цели. У вас нет такой возможности, если все находится в одной большой куче ресурсов. Это не то, к чему привыкли люди, но в этом нет ничего обременительного.
В дополнение к фактору простоты, упомянутому другим респондентом, многие программы на Си написаны одним человеком.
Когда у вас есть группа людей, становится желательным разделить приложение на несколько исходных файлов, чтобы избежать необоснованных конфликтов в изменениях кода. Особенно, когда над проектом работают как продвинутые, так и начинающие программисты.
Когда один человек работает сам по себе, это не проблема.
Лично я использую несколько файлов на основе функций как привычную вещь. Но это только я.
Потому что у C89 не было inline
функций. Это означало, что разбиение вашего файла на функции приводило к дополнительным затратам на перенос значений в стек и перепрыгивание. Это добавило много накладных расходов при реализации кода в 1 большом операторе switch (цикл обработки событий). Но цикл обработки событий всегда намного сложнее реализовать (или даже правильно), чем более модульное решение. Поэтому для крупных проектов люди все равно отказались бы от модульности. Но когда они заранее продумали дизайн и смогли контролировать состояние в 1 операторе switch, они сделали это.
В настоящее время, даже в C, не нужно жертвовать производительностью для модульности, потому что даже в C функции могут быть встроенными.
inline
ключевого слова в компиляторах C89, не может быть встроенным, поэтому вам пришлось писать все в одной гигантской функции, что неверно. Вы не должны использовать inline
оптимизацию производительности - компилятор, как правило, будет знать лучше, чем вы (и может игнорировать ключевое слово).
inline
Ключевое слово компоновщика связанного с семантикой , которые являются более важными , чем вопрос о том, следует ли выполнять в линии оптимизацию, но некоторые реализации имеют другие директивы для контроля качества в подкладке и такие вещи иногда могут быть очень важны. В некоторых случаях функция может выглядеть так, как будто она слишком велика, чтобы ее можно было встроить, но постоянное свертывание может уменьшить размер и время выполнения практически до нуля. Компилятор, которому не дают сильного толчка, чтобы поощрить
Это считается примером эволюции, которая, как я удивляюсь, еще не упоминалась.
В темные дни программирования компиляция одного ФАЙЛА могла занимать минуты. Если бы программа была модульной, то включение необходимых файлов заголовков (без предварительно скомпилированных параметров заголовков) было бы значительной дополнительной причиной замедления. Кроме того, компилятор может выбрать / нужно сохранить некоторую информацию на самом диске, возможно, без использования файла автоматической замены.
Привычки, которые эти факторы окружающей среды привели к продолжению практики развития и только постепенно адаптировались с течением времени.
В то время выигрыш от использования одного файла был бы аналогичен тому, который мы получаем при использовании SSD вместо HDD.