У меня есть два заголовочных файла main.h
и submodule.h
. По разным причинам я не могу просто включить один из этих заголовков в другой.
Тогда сделайте себе одолжение и исправьте это, даже если вы на самом деле не #include "submodule.h"
внутри main.h
. Ваше заявление, что вы не можете этого сделать, имеет очень неприятный запах.
submodule.c
реализует этот массив:
const INDEX_TABLE_t INDEX_TABLE {/* 42 random char values */};
Похоже, вы пропустили =
перед инициализатором. Кроме того, с INDEX_TABLE_t
, являющимся типом массива с const
элементами, я не думаю, что дополнительные const
там имеют какой-либо дополнительный эффект.
Мой клиент использует инструмент анализа кода (QA-C), который жалуется на
удвоенное определение типа INDEX_TABLE_t.
[C] More than one declaration of 'INDEX_TABLE_t' (with no linkage).
Я полагаю, что инструмент обеспокоен именно тем, что объявление повторяется в отдельных файлах, а не централизовано в одном заголовке. Это действительная проблема не столько для программы сейчас , сколько для постоянного обслуживания и развития. Вы установили ловушку для будущего сопровождающего (возможно, будущего для вас), в которой они могут изменить только одно из определений типов или изменить их несовместимыми способами, что приведет к незначительной, но значимой ошибке.
Клиент поручил мне изменить код, чтобы эта ошибка не
выдан инструментом анализа кода.
Обычно я решаю эту проблему, добавляя ключевое слово extern ко всем, кроме одного
вхождение. Но в этом случае компилятор выдает исключение:
error: conflicting specifiers in declaration of 'INDEX_TABLE_t'
Но декларации равны (они отображаются на основе модели).
INDEX_TABLE_t
обозначает тип , а не объект или функцию. У него не может быть внешней связи (на extern
), потому что она автоматически и обязательно имеет нет связи.
Есть ли у меня шанс порадовать и компилятор, и код
анализатор?
Да.
Создает ли другой заголовочный файл для включения в main.h или все
другие * .h файлы мой единственный вариант?
Не совсем, но вам нужно поместить определение типа в один заголовок, и все ваши источники получат его оттуда, прямо или косвенно. Одной из альтернатив вашей идеи может быть #include
этот заголовок непосредственно в ваших .c файлах, что, вероятно, потребует тщательного управления порядком ваших #include
операторов.
Но в целом, похоже, что ваша коллекция заголовков может выиграть от некоторого рефакторинга. Как правило, каждый заголовок должен (и должен иметь возможность) включать все заголовки, необходимые для предоставления объявлений для идентификаторов, используемых, но не объявленных внутри, и никаких других заголовков. Отчасти это облегчается использованием защитных элементов в каждом заголовке. У этой работы могут быть и другие аспекты, если вы не разрабатывали ее с самого начала, но это, безусловно, можно сделать.
В ответ на отредактированный вопрос
То, что некоторые сборки программного обеспечения не включают подмодуль , но (предположительно) действительно используют main.h
, является убедительным признаком того, что main.h
является неправильным местом для typedef
для типа объект, из которого только субмодуль предоставляет экземпляр. Он должен идти в заголовке, связанном с субмодулем или более широко с коллекцией различных источников, которые все используют этот атрибут субмодуля .
Возможно, этот заголовок может быть submodule.h
сам. Возможно, это должен быть отдельный заголовок, скажем submodule_general.h
, который может быть даже лучшим местом для некоторых других вещей, которые теперь есть и в submodule.h
. Возможно, в submodule.h
есть вещи, которые не должны быть там, и удаление их - возможно, в сочетании с преобразованием некоторых объектов и функций из внешних во внутренние - сделало бы более приемлемым включение submodule.h
в большее количество мест.
Несмотря на то, что вы разделяете объявления между заголовками, чтобы избежать дублирования и служить каким-либо другим целям, которые у вас есть, у вас всегда есть варианты включения заголовков в источники, которые в них нуждаются, либо напрямую, либо косвенно через другие заголовки.