Подтвердить что ты не робот

Какие существуют методы модуляции кода C?

Какие методы, практики и соглашения вы знаете для модульного кода C, поскольку проект растет в размерах?

4b9b3361

Ответ 1

Создайте заголовочные файлы, содержащие ТОЛЬКО то, что необходимо для использования модуля. В соответствующем .c файле (файлах) сделайте все, что не должно быть видимым снаружи (например, вспомогательные функции) static. Используйте префиксы для имен всех видимых извне, чтобы избежать конфликтов пространства имен. (Если модуль охватывает несколько файлов, все становится сложнее.), Поскольку вам может потребоваться выставить внутренние вещи и не скрыть их со "статическими" )

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

Ответ 2

Методы OO могут применяться к коду C, они требуют большей дисциплины.

  • Используйте непрозрачные ручки для работы с объектами. Хорошим примером того, как это делается, является библиотека stdio - все организовано вокруг непрозрачного дескриптора FILE*. Вокруг этого принципа организовано много успешных библиотек (например, zlib, apr)
  • Поскольку все члены struct неявно public в C, вам нужна дисциплина конвенции + программиста, чтобы применить полезную технику скрытия информации. Выберите простое, автоматически проверяемое соглашение, такое как "частные члены заканчиваются на" _ ".
  • Интерфейсы могут быть реализованы с использованием массивов указателей на функции. Конечно, для этого требуется больше работы, чем в таких языках, как С++, которые обеспечивают поддержку на языке, но все же это можно сделать на C.

Ответ 4

  • Не определять переменные в файлах заголовков; вместо этого определите переменную в исходном файле и добавьте выражение extern (объявление) в заголовок. Это будет связано С# 2 и # 3.
  • Используйте заголовок include для каждого заголовка. Это спасет так много головных болей.
  • Предполагая, что вы сделали # 1 и # 2, включите все, что вам нужно (но только то, что вам нужно) для определенного файла в этом файле. Не зависеть от того, как компилятор расширяет ваши включенные директивы.

Ответ 5

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

Затем, чтобы обработать свободное соединение плагина, связанного с остальной частью приложения (так как было бы неплохо, если бы оно что-то делало между установкой и отключением), у них есть сигнальная система. Плагины могут регистрировать обратные вызовы, которые будут вызываться, когда определенные сигналы (не стандартные сигналы C, но пользовательский расширяемый вид [идентифицируется строкой, а не установленными кодами]) выдается любой частью приложения (включая другой плагин). Они также могут сами выдавать сигналы.

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

Ответ 6

Функция должна делать одно и хорошо делать это.

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

Создавайте небольшие модули с несколькими функциями. Выставляйте только то, что вам нужно, сохраняйте что-то еще статическое внутри модуля. Свяжите небольшие модули вместе со своими файлами интерфейса .h.

Предоставлять функции Getter и Setter для доступа к переменным области видимости статического файла в вашем модуле. Таким образом, переменные записываются только в одном месте. Это также помогает отслеживать доступ к этим статическим переменным, используя точку останова в функции и стеке вызовов.

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

Я всегда стараюсь держать переменные в их самом узком объеме, также в пределах функций. Например, индексы для циклов for обычно могут храниться в масштабе блока и не должны подвергаться воздействию всего функционального уровня. C не такой гибкий, как С++, с "определите его, где вы его используете", но он работоспособен.

Ответ 7

Прерывание кода в библиотеках связанных функций - это один из способов сохранения вещей. Чтобы избежать конфликтов имен, вы также можете использовать префиксы, чтобы вы могли повторно использовать имена функций, хотя с хорошими именами я никогда не считал, что это большая проблема. Например, если вы хотите разработать свои собственные математические процедуры, но по-прежнему используете некоторые из стандартной математической библиотеки, вы можете префикс вашей строки: xyz_sin(), xyz_cos().

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

Ответ 8

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