Що розміщувати в заголовки

Коли я розмовляю з Сі програмістами про апаратні інтерфейси або стандарті програмування, я часто бачу, що вони не володіють необхідними навичками та інформацією про цю мову програмування. Як правило, це тому, що всі ми в основному інженери-електронники, які вивчали Сі (або який-небудь іншу мову) самостійно.

Один з таких навичок відноситься до створення заголовків файлів. Що потрібно (або не потрібно) розміщувати в заголовному Сі файлі .h? Коли потрібно створювати заголовки? І чому?

На перераховані питання у мене є свій список відповідей.

Створюйте один заголовки .h для кожного "модуля" системи. Модуль може містити один або кілька компільованих файлів (наприклад. З або .asm), але він повинен реалізовувати тільки один аспект системи. Прикладами добре підібраних модулів є: драйвер для АЦП; комунікаційний протокол, такий як FTP; менеджер аварій, який веде журнал помилок і попереджає про них користувача.

Включайте в заголовки .h все прототипи функцій, які складають зовнішній інтерфейс модуля. Наприклад, заголовки adc.h міг би містити прототипи функцій adc_init (), adc_select_input (), adc_read ().

Не вмикайте в заголовки функції і макроси, які призначені для використання всередині модуля. Бажано приховати цих внутрішніх "помічників", якщо вони не використовуються в інших модулях. (Якщо ваш модуль складається з декількох компільованих файлів, які використовують ці внутрішні функції, тоді створіть окремий заголовки для цих цілей.) Модуль А повинен викликати модуль B тільки через відкритий інтерфейс, визначений в заголовки moduleb.h

Не ставте в заголовки змінні, як це занадто часто робиться за допомогою ключового слова extern. Правильна інкапсуляція модуля вимагає приховування всіх внутрішніх даних всередині вихідних Сі файлів. По можливості внутрішні змінні потрібно оголошувати з ключовим словом static, щоб обмежити їх область видимості межами модуля.

Чи не розкривайте внутрішній формат специфічних структур даних, використовуваних інтерфейсними функціями модуля. Іншими словами, в заголовки не повинно бути ніяких structfoo. Якщо у вас є тип даних, який потрібно передати в або з модуля, визначте типи даних в заголовки через typedef. Наприклад, так "typedef struct foo moduleb_type". Клієнтські модулі не повинні знати внутрішній формат структур.

Незважаючи на те, що ці поради не є специфічними для вбудованого програмного забезпечення. я сподіваюся, що вони виявляться для вас корисними.