Дублирование определения препроцессора - PullRequest
0 голосов
/ 10 января 2019

У меня есть две библиотеки, и, к сожалению, они определяют два идентичных определения препроцессора (которые мне нужно использовать):

lib1.h

#define MYINT 1

lib2.h

#define MYINT 2

В моей программе мне нужно использовать оба из них:

#include <Lib1.h>
#include <lib2.h>
...
int myint = MYINT;

И здесь у меня ошибка, что MYINT не может быть решена.

Как мне решить эту проблему, если я не могу изменить файлы lib?

Ответы [ 4 ]

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

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

Итак, создайте включаемый файл из lib1.h с именем lib1_ext.h, содержащий следующие строки:

#if !defined(MYLIB1_EXT_H_INCLUDED)
#define MYLIB1_EXT_H_INCLUDED
// ensure that MYINT is not defined no matter what order the include files are used
#undef MYINT
#include "lib1.h"
const int myInt_lib1 = MYINT;  // make a copy of the value of MYINT if it is needed
// make sure MYINT is undefined to allow the compiler to catch any dependencies on it
#undef MYINT
#endif

и аналогично для lib2.h создать lib2_ext.h как в:

#if !defined(MYLIB2_EXT_H_INCLUDED)
#define MYLIB2_EXT_H_INCLUDED
// ensure that MYINT is not defined no matter what order the include files are used
#undef MYINT
#include "lib2.h"
const int myInt_lib2 = MYINT;  // make a copy of the value of MYINT if it is needed
// make sure MYINT is undefined to allow the compiler to catch any dependencies on it
#undef MYINT
#endif

теперь при использовании любой из функций библиотеки используйте соответствующую копию значения MYINT, myInt_lib1 при использовании функции lib1.h и / или myInt_lib2 при использовании функции lib2.h. Однако, если MYINT используется только с самим файлом заголовка библиотеки и нигде не нужен для фактического использования библиотеки, тогда вы можете просто отказаться от этого оператора.

См. Также Можно ли переопределить макрос C ++, а затем определить его обратно? , который показывает, как сохранить и восстановить определение макроса с помощью компиляторов некоторых поставщиков и директивы pragma. Это не похоже на то, что это действительно применимо к вашей публикации.

Эта публикация также содержит ответ, который описывает основы расширения макросов и почему const int myInt_lib1 = MYINT; необходим для сохранения значения MYINT вместо использования препроцессора, как в #define MYINT_LIB1 MYINT, для сохранения значения MYINT , Препроцессор задерживает расширение макроса как можно дольше, и в результате попытка использовать макрос препроцессора, как в #define MYINT_LIB1 MYINT для сохранения значения MYINT, не работает, если MYINT не определено с помощью #undef директива. Когда препроцессор сначала заменяет текст MYINT_LIB1 на текст MYINT, а затем выполняет повторное сканирование, поскольку MYINT теперь не определено, текст MYINT остается, и в случае неудачи получается ошибка компилятора.

Одна вещь, которую следует рассмотреть с этой работой вокруг

Это обходное решение предполагает, что все, что нужно, это числовое значение MYINT, которое обрабатывается как постоянное значение int. Таким образом, предполагается, что места, где используется MYINT, - это места, где также можно использовать const int.

Это означает, что любой вид вставки токена, #if test или другое действие препроцессора, которое включает обработку текста, который MYINT определен как текст, который может использоваться препроцессором для других макроопераций, не будет работать должным образом за пределами мест, где lib.h или lib2.h включены и обработаны препроцессором.

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

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

Примером возможной зависимости может быть макрос внутри lib1.h, который использует MYINT для создания дополнительного невидимого аргумента функции, как в:

int funcStuff (int a, struct b *pBthing);

#define FUNCSTUFF (pBthing)  funcStuff(MYINT, (pBthing))

с ожиданием, что любой, кто использует библиотеку, будет использовать FUNCSTUFF(&bThing); вместо funcStuff (MYINT, &bThing);. Чтобы это работало, вам нужно либо использовать функцию funcStuff() напрямую, как в funcStuff(myInt_lib1, &bThing);, либо создать собственную версию макроса FUNCSTUFF(), использующего myInt_lib1 вместо MYINT.

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

Вы можете #undef MYINT, прежде чем включить заголовок в качестве обходного пути.

#undef MYINT
#include <Lib1.h>
const int myint_lib1 = MYINT; // 1

#undef MYINT
#include <lib2.h>
const int myint_lib2 = MYINT; // 2
0 голосов
/ 22 января 2019

Без трюков препроцессора:

lib1_handler.h

extern int lib1_handler_myint;
// or
int lib1_handler_myint_f();

lib1_handler.c

#include <Lib1.h>

int lib1_handler_myint = MYINT;
// or
int lib1_handler_myint_f() { return MYINT; }

lib2_handler.h

extern int lib2_handler_myint;
// or
int lib1_handler_myint_f();

lib2_handler.c

#include <Lib2.h>

int lib2_handler_myint = MYINT;
// or
int lib2_handler_myint_f() { return MYINT; }

main.c

#include "lib1_handler.h"
#include "lib2_handler.h"

int void () {
  return lib1_handler_myint || lib2_handler_myint_f();
}
0 голосов
/ 10 января 2019

Получите значение MYINT первой библиотеки, прежде чем вторая заменит ее.

#include <Lib1.h>
int myInt1 = MYINT;
#undef MYINT
#include <lib2.h>
int myInt2 = MYINT;
#undef MYINT

Конечно, это не сработает, если MYINT является чем-то динамичным, и вам нужно держать его фактический контент вокруг.

Отредактировано handy999: без точки с запятой в конце инструкций препроцессора.

...