Как отключить макросы, импортированные из C-заголовка
Класс A использует библиотеку, написанную в C. Эта библиотека предоставляет некоторые типы данных и константы, которые используются в A. К сожалению, библиотека также определяет макросы в своем заголовочном файле, которые сталкиваются с моим кодом на С++ в main.cpp или в других классах с использованием A.
Как я могу предотвратить выполнение макросов c_library.h, когда A.h где-то включен? Я также был бы открыт для архитектурных изменений, но я бы предпочел не прикасаться к библиотеке C.
Конечно, есть директива #undef. Но это означало бы большую ручную работу для каждого макроса или для каждого столкновения. (Хорошо, их не так уж много, но эй, это должно быть возможно более элегантно?)
код:
//main.cpp
#include "A.h"
...
A a(...)
...
std::max(x, y); // oops, problem since max is defined as macro in c_library.h
...
//A.h
#include "c_library.h"
class A{
public:
A(...);
static void callbackForCLibrary(datatypeOfCLibrary d){...}
private:
private datatypeOfCLibrary1;
private datatypeOfCLibrary2;
}
Ответы
Ответ 1
Вы уже знаете о параметре #undef
, который будет делать то, что вам нужно.
Однако есть и другой вариант. Вы можете полностью скрыть тот факт, что ваш A
использует библиотеку C
у ваших пользователей: определите свои собственные типы и интерфейс в определении заголовка и класса A
и удалите библиотеку из заголовка A
. Затем в вашем файле реализации вы можете включить заголовок библиотеки и использовать библиотеку любым способом, все время скрывая включение c_library.h
от ваших пользователей. Это дает дополнительное преимущество в уменьшении связи между пользователями вашего класса, вашим классом и библиотекой, от которой оно зависит.
Ответ 2
Вы можете создать "wrap_c_library.h", что-то вроде:
#ifndef WRAP_C_LIBRARY_H
#define WRAP_C_LIBRARY_H
#include "c_library.h"
#undef TROUBLESOME_MACRO_FROM_C_LIBRARY
#endif // WRAP_C_LIBRARY_H
Ответ 3
Потенциально (не уверен, насколько хорошо это будет работать на практике) #undef
не обязательно означает ручную работу - вы можете автоматически сгенерировать второй файл, включив в него #undef
все определения из первого заголовка.
например. с учетом этого заголовка:
#define A(X, Y) [X ; Y]
#define B(X, Y) {X...Y}
#define C this is C
#define D this is D
... запустите следующий короткий script:
gcc -undef -dN -E foo.h > undef_foo.h
sed -i ".bak" 's/#define[ \t]\([A-Za-z0-9_]*\)/#undef \1/g' undef_foo.h
gcc -undef -dD -E - < /dev/null >> undef_foo.h
sed -i ".bak" '/#[du]/!d' undef_foo.h
... для создания этого встречного заголовка:
#undef __STDC__
#undef __STDC_HOSTED__
#undef __DYNAMIC__
#undef A
#undef B
#undef C
#undef D
#define __STDC__ 1
#define __STDC_HOSTED__ 1
#define __DYNAMIC__ 1
Основная идея: получить список всех определений, которые являются следствием включения foo.h
. Параметры -undef -dN
для GCC минимизируют количество предоставленных системой материалов, которые будут включены в этот список (до трех для меня, не уверен, насколько это согласовано), чтобы минимизировать залог и упростить вывод. Затем замените все строки #define
на эквивалентные строки #undef
(-dN
делает это проще, не перечисляя замены). Затем добавьте все макроопределенные макросы, которые GCC по-прежнему включается в конец файла, поэтому их значения восстанавливаются. Наконец, удалите все директивы из файла, которые не являются #define
или #undef
.
Использование:
#include "foo.h"
#include "undef_foo.h"
A(1, 2)
B(3, 4)
C
D
Запустите gcc -E
и наблюдайте, как макросы не расширяются.
Кто-то с лучшими навыками написания сценариев, вероятно, может сделать это намного лучше, но это основная идея.
Ответ 4
Вы можете использовать директивы препроцессора #ifdef
и #undef
для обнаружения функций, которые вы хотите вызывать на С++, и отключить встречные макросы, объявленные в C-заголовке
Ответ 5
1) Для любого конкретного макроса вы можете "отключить" его с помощью #undef
.
2) Если вам не нужны ЛЮБЫЕ определения из определенного заголовка: просто не #include
это.
3) Если заголовок неявно включен из чего-то другого, и вы все же хотите "отключить" весь заголовок, вы можете #define
защитить заголовок перед первым включением.
4) Я не могу представить, чтобы какой-либо из этих параметров применим к "std:: max()":
http://en.cppreference.com/w/cpp/algorithm/max
Ответ 6
Другой подход заключается в добавлении нового макропереключателя в проблемный файл "DO_NOT_DEFINE_MACROS"
Измените проблемный файл, чтобы НЕ определять макросы, если этот макрос определен,
Затем, прежде чем включить его, определите макрос, включите файл, затем отмените определение макроса.