Подтвердить что ты не робот

Как временно отключить расширение макросов в C/С++?

По какой-то причине мне нужно временно отключить некоторые макросы в заголовочном файле, а #undef MACRONAME сделает компиляцию кода, но он будет отменять существующий макрос.

Есть ли способ просто отключить его?

Я должен упомянуть, что вы действительно не знаете значения макросов и что я ищу решение кросс-компилятора (должно работать хотя бы в GCC и MSVC).

4b9b3361

Ответ 1

В MSVC вы можете использовать push_macro pragma, GCC поддерживает для совместимости с компиляторами Microsoft Windows.

#pragma push_macro("MACRONAME")
#undef MACRONAME

// some actions

#pragma pop_macro("MACRONAME")

Ответ 2

Используя только средства, определенные стандартом C (C89, C99 или C11), единственным механизмом "отключить" является #undef.

Проблема в том, что механизм "повторного включения" отсутствует.


Как указывали другие, если заголовочный файл, содержащий определения макросов, структурирован так, что он не содержит деклараций typedef или enum (их нельзя повторить, объявления функций и переменных можно повторить), тогда вы могли бы #undef макрос, сделайте то, что вам нужно, без действующего макроса, а затем повторно включите заголовок, возможно, после отказа от его защиты от повторного включения.

Если макросы не определены в заголовке, вы, конечно, застреваете, пока не будете реорганизовать код так, чтобы они были в заголовке.

Доступен еще один трюк - если макросы являются функциональными макросами, а не объектно-ориентированными макросами.

#define nonsense(a, b)   b /\= a

int (nonsense)(int a, int b)
{
    return (a > b) ? a : b;
}

Функция nonsense() определена отлично, несмотря на макрос непосредственно перед ним. Это связано с тем, что макро-вызов - для макрофайла, подобный функции, должен немедленно сопровождаться открытой скобкой (давать или принимать пустое пространство, возможно, включая комментарии). В строке определения функции токен после "бессмыслицы" является закрывающей скобкой, поэтому он не является вызовом макроса nonsense.

Если бы макрос был объектно-ориентированным макросом без аргументов, трюк не сработал бы:

#define nonsense min

int (nonsense)(int a, int b)
{
    // Think about it - what is the function really called?
    return (a > b) ? a : b;
}

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

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

Ответ 3

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

Ответ 4

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

#include <foo.h> // declares macro FOO

// Do things with FOO

#undef FOO

// do things without FOO

#include <foo.h> // reenable FOO

Затем ваш заголовок должен быть сконструирован вдоль этих строк

#ifndef FOO
#define FOO do_something(x,y)
#endif

Ответ 5

EDIT:

Вы можете подумать, что это легко:

#ifdef macro
#define DISABLED_macro macro
#undef macro
#endif

// do what you want with macro

#ifdef DISABLED_macro
#define macro DISABLED_macro
#endif

Но это не так (как показано в следующем примере)!

#include <iostream>
#include <limits>

#include <windows.h>

#ifdef max
#define DISABLED_max max
#undef max
#endif

int main()
{
    std::cout << std::numeric_limits<unsigned long>::max() << std::endl;

#ifdef DISABLED_max
#define max DISABLED_max
#endif

    std::cout << max(15,3) << std::endl;  // error C3861: "max": identifier not found
    return 0;
}

Использование #undef в макросе и повторное включение исходного заголовка также вряд ли будет работать из-за защиты заголовков. Итак, что осталось с помощью директив push_macro/pop_macro #pragma.

#pragma push_macro("MACRO")
#undef MACRO
// do what you want
#pragma pop_macro("MACR")