как поделиться определением типа массива без общего заголовочного файла? - PullRequest
0 голосов
/ 08 января 2019

Положение

Я использую компилятор min GW:

>bin\cpp --version
cpp.exe (GCC) 6.1.0
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

У меня есть два заголовочных файла main.h и submodule.h. По разным причинам я не могу просто включить один из этих заголовков в другой.


[обновление]

Я думаю, вам нужно объяснить различные причины, по которым вы не можете просто включить один из этих заголовков в другой, потому что это очевидный ответ ... - Эндрю

  • Я не могу импортировать main.h в submodule.h, потому что в этом случае изменение main.h вызовет перекомпиляцию субмодуля, хотя здесь ничего не изменилось. Время компиляции является серьезной проблемой для моего клиента.

  • Я не могу включить submodule.h в main.h, потому что submodule.h определяет множество вещей, но только несколько определений являются публичными. Мой клиент хочет максимально уменьшить видимость идентификаторов.

  • Мой клиент использует содержимое main.h для проверки совместимости различных версий целевого программного обеспечения. Наличие и размер упомянутого массива является одним из критериев совместимости. Поэтому определение массива должно оставаться в main.h

  • В некоторых версиях целевого программного обеспечения отсутствует подмодуль . Поэтому файлы, создающие этот подмодуль, могут присутствовать или не присутствовать. Для моего клиента есть много накладных расходов, связанных с этой ситуацией, которую должен сделать кто-то другой, а не я. Таким образом, мой клиент также хочет ограничить количество «мерцающих» файлов.


У меня также есть много других *.h файлов, которые включают main.h, но не submodule.h, и они не должны скрывать некоторые вещи в субмодуле.

submodule.h определяет множество вещей, реализованных в submodule.c. Среди них определение типа массива и глобальная переменная этого типа:

typedef const char INDEX_TABLE_t[42]; 
const INDEX_TABLE_t INDEX_TABLE;

submodule.c реализует этот массив:

const INDEX_TABLE_t INDEX_TABLE {/* 42 random char values */};

Переменная INDEX_TABLE используется в других *.h файлах:

char SOME_OTHER_INDEX[23] = {/* 23 random char values */};

#define SELECTOR_VALUE 5
#define a_fix_name INDEX_TABLE[SOME_OTHER_INDEX[SELECTOR_VALUE]]

эти *.h файлы включают main.h, но не submodule.h.

Поэтому я использовал (точно такое же) определение типа INDEX_TABLE_t и INDEX_TABLE_t к main.h, что прекрасно компилируется.

Проблема

Мой клиент использует инструмент анализа кода (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'

Но декларации равны (они отображаются на основе модели).

Вопросы

Есть ли у меня шанс порадовать и компилятор, и анализатор кода?

Является ли создание другого заголовочного файла для включения в main.h или всех других *.h файлов моим единственным вариантом?

1 Ответ

0 голосов
/ 08 января 2019

У меня есть два заголовочных файла 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 в большее количество мест.

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

...