Рекомендации для руководящих принципов архитектуры проекта "C"?

Теперь, когда я получил свою голову, обернутую вокруг языка "C", до такой степени, что я достаточно хорошо разбираюсь в написании чистого кода, я хотел бы сосредоточить свое внимание на руководящих принципах архитектуры проекта. Я ищу хороший ресурс, который освещает следующие темы:

  • Как создать интерфейс, который повышает удобство обслуживания кода и расширяется для будущих обновлений.
  • Рекомендации по созданию библиотеки. Пример, когда следует рассмотреть использование статических vs динамических библиотек. Как правильно спроектировать ABI, чтобы справиться с любым из них.
  • Заголовочные файлы: что разделить и когда. Примеры о том, когда использовать 1:1 против 1: много .h на .c
  • Все, что вы чувствуете, я пропустил, но важно, когда вы пытаетесь создать новый проект C.

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

Какой ресурс вы бы порекомендовали для таких тем?

Ответы

Ответ 1

Всякий раз, когда мне приходилось серьезно писать C-код, мне пришлось подражать С++-функциям. Главное, что стоит сделать:

  • Подумайте о каждом модуле, таком как класс. Функции, которые вы публикуете в заголовке, похожи на общедоступные методы. Только поместите функцию в заголовок, если ей нужен интерфейс.

  • Избегайте круговых зависимостей модуля. Модуль A и модуль B не должны звонить друг другу. Вы можете реорганизовать что-то в модуль C, чтобы этого избежать.

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

  • Избегайте переменных области видимости модуля - ранее описанный шаблон обычно делает то, что вам нужно. Но если вам действительно нужны переменные модуля, сгруппируйте их по структуре, хранящейся в одной переменной модуля, называемой "m" или что-то непротиворечивое. Затем в вашем коде всякий раз, когда вы видите "m.variable", вы сразу поймете, что это одна из структурных областей.

  • Чтобы избежать проблем с заголовком, введите #ifndef MY_HEADER_H #define MY_HEADER_H декларация, которая защищает от двойного включения. Файл .h для заголовка вашего модуля должен содержать только #includes, необходимый для этого ФАЙЛА HEADER. У модуля .c файла может быть больше всего необходимых для компиляции модуля, но не добавлять их в заголовочный файл модуля. Это избавит вас от многих конфликтов пространства имен и проблем с порядком включения.

Ответ 2

Истины о системах архитекторов являются вневременными, и они пересекают границы языка. Вот небольшой совет, посвященный C:

  • Каждый модуль скрывает секрет. Создайте свою систему вокруг интерфейсов, которые скрывают информацию от своих клиентов. C только скрытая по типу информации скрытая конструкция - это указатель на неполную структуру. Изучите его тщательно и часто используйте его.

  • Один интерфейс для реализации - хорошее эмпирическое правило. (Интерфейс -.h, реализация -.c.) Иногда вам нужно предоставить два интерфейса, которые относятся к одной и той же реализации: тот, который скрывает представление, и тот, который предоставляет его.

  • Вам понадобятся соглашения об именах.

Превосходная модель управления этими проблемами в C - это Dave Hanson C Интерфейсы и реализации. В нем вы узнаете, как создавать хорошие интерфейсы и реализации, и как один интерфейс может строить на другом, чтобы сформировать связную библиотеку. Вы также получите отличный набор начальных интерфейсов, которые вы можете использовать в своих приложениях. Для кого-то на вашем месте, , я не могу рекомендовать эту книгу слишком высоко. Это архетип хорошо продуманных систем в C.

Ответ 3

Чистота пространства имен - особенно важна для библиотек. Приоритет ваших публичных функций с именем библиотеки, в некотором роде. Если ваша библиотека была названа "happyland", создайте такие функции, как "happyland_init" или даже "hl_init".

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

Для библиотек реентерабель также имеет решающее значение. Не зависимо от глобального состояния, которое не является разделенным (вы можете иметь маркер структуры typedef, чтобы сохранить это состояние, если это необходимо).

Ответ 4

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

Вот некоторые из моих известных советов, которые я могу вам дать.

Ответ 5

Как создать интерфейс, который повышает удобство обслуживания кода и расширяемый для будущих обновлений.

Предоставляя как можно меньше деталей реализации. Например,