Как разрешить конфликты переменных в файлах заголовков?

#c #visual-studio-2017

#c #visual-studio-2017

Вопрос:

Я пишу адаптивный алгоритм обновления размера шага в OpenSees (проект моделирования землетрясений с открытым исходным кодом, написанный в основном в Visual Studio c ). Я столкнулся с конфликтом между двумя переменными, имеющими одинаковое имя в двух разных файлах заголовков (а именно, windef.h и steelz01.h). Мне нужен способ разрешить этот конфликт.

Я использую gnuplot-iostream.h в своем проекте, я сталкиваюсь с этим конфликтом только тогда, когда включаю этот файл заголовка, в противном случае конфликта нет, код собран идеально.

По сути, gnuplot-iostream.h вызывает windows.h, который в дальнейшем вызывает windef.h. Я добавил параметры включения в файл steelz01.h, но это не решило проблему.

Когда я меняю имя varaibale в steelz01.h на другое имя, код также отлично строится. ПРОБЛЕМА не найдена. Но я не хочу указывать имя переменной в steelz01, это имеет серьезные последствия.

Я включаю файлы заголовков, подобные этому

 #include "gnuplot-iostream.h"
#include <SteelZ01.h>
  

Вот как размер переменной определяется в steelz01

 #define LOOP_NUM_LIMIT               30
const int SIZE = LOOP_NUM_LIMIT; //limit of array number
  

и в windef.h это определяется следующим образом

 typedef struct tagSIZE
{
    LONG        cx;
    LONG        cy;
} SIZE, *PSIZE, *LPSIZE;

typedef SIZE               SIZEL;
typedef SIZE               *PSIZEL, *LPSIZEL;
  

Visual Studio 2017 выдает эту ошибку,

 1>c:program files (x86)windows kits8.1includesharedwindef.h(190): error C2378: 'SIZE': redefinition; symbol cannot be overloaded with a typedef

1>e:phd working folder0_ops_githubsrcmaterialndreinforcedconcreteplanestresssteelz01.h(17): note: see declaration of 'SIZE'
  

Я ожидаю способ разрешить этот конфликт и успешную сборку.

Комментарии:

1. Для чего вам нужна переменная SIZE для начала? Почему вы не можете использовать макрос? И еще лучше, замените макрос соответствующей постоянной переменной.

2. Экспорт переменной с именем just SIZE является серьезной проблемой. Это плохой дизайн, с которым другим программистам приходится бороться позже. Решение на C — используйте namespace SteelZ01 { . И не используйте #define , используйте static constexpr .

3. Как я уже говорил, это проект с открытым исходным кодом (статическая библиотека), авторы steelz01 определили его таким образом. Я могу изменить определение SIZE , но проблема в том, что мне нужно изменить имя переменной во всех наследствах steelz01

4. Затем вы должны сообщить об этом как об ошибке авторам проекта.

5. #define это не столько ошибка, сколько то, чего вам следует избегать. #define вызывает простую замену текста, которая выполняется до начала компиляции компилятором. Везде, где LOOP_NUM_LIMIT существует в коде, он бездумно заменяется на 38. Этот я считаю достаточно безопасным, но в нем нет необходимости.

Ответ №1:

Я бы посоветовал вам поместить оператор include в пространство имен,

 namespace ABC
{
    #include "gnuplot-iostream.h"
}

namespace PQR
{
   #include <SteelZ01.h>
}
  

Вызов:

 ABC::SIZE
PQR::SIZE
  

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

Комментарии:

1. Это интересно. Я буду реализовывать файлы заголовков в пространстве имен и дам вам знать об этом. Большое вам спасибо

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

3. Ни один файл заголовка не содержит только объявлений. У меня есть отдельный файл .cpp, который состоит из всех определений функций-членов. Есть ли у этого подхода к пространству имен какие-либо проблемы??

4. Это будет рассматривать определение и объявление отдельно. Я не думаю, что это создаст проблему.

5. Это действительно плохая идея. Если он компилируется, он сообщает компилятору, что все имена, которые объявлены в этом заголовке, будут определены в этом пространстве имен. Но исходный файл, который определяет эти имена, ничего не знает об этом пространстве имен, и его определений, безусловно, в нем не будет. Не лги компилятору. И, да, если это библиотека «только для заголовков» со всеми встроенными функциями, то она может компилироваться и связываться. Но в результате у вас будет две версии каждой функции, определенной в этом заголовке, одна внутри пространства имен, а другая нет. Удачи в отладке.