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

5 ответов

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

#pragma push_macro("MACRONAME")
#undef MACRONAME

// some actions

#pragma pop_macro("MACRONAME")
83
ответ дан 27 November 2019 в 04:09
поделиться

Using just the facilities defined by Standard C (C89, C99 or C11), the only 'disable' mechanism is #undef.

The problem is there is no 're-enable' mechanism.


As others have pointed out, if the header file containing the macro definitions is structured so that it does not contain any typedef or enum declarations (these cannot be repeated; function and variable declarations can be repeated), then you could #undef the macro, do what you need without the macro in effect, and then re-include the header, possibly after undefining its protection against reinclusion.

If the macros are not defined in a header, of course, you are stuck until you refactor the code so that they are in a header.

One other trick is available - if the macros are function-like macros and not object-like macros.

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

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

The function nonsense() is defined fine, despite the macro immediately before it. This is because a macro invocation - for a function-like macro - must be immediately followed by an open parenthesis (give or take white space, possibly including comments). In the function definition line, the token after 'nonsense' is a close parenthesis, so it is not an invocation of the nonsense macro.

Had the macro been an argument-less object-like macro, the trick would not work:

#define nonsense min

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

This code defines a bogus function that's called min and is nonsensical. And there's no protection from the macro.

This is one of the reasons why the standard is careful to define which namespaces are reserved for 'The Implementation'. The Implementation is allowed to define macros for any purpose it desires or needs, of any type (function-like or object-like) it desires or needs, provided those names are reserved to the implementation. If you as a consumer of the services of The Implementation try to use or define a name reserved to the implementation, you must be aware that your code will probably break sooner or later, and that it will be your fault, not the fault of The Implementation.

28
ответ дан 27 November 2019 в 04:09
поделиться

РЕДАКТИРОВАТЬ:

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

#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 на макрос и повторное включение исходного заголовка также вряд ли будут работать из-за защиты заголовка. So what's left is using the push_macro/pop_macro #pragma directives.

#pragma push_macro("MACRO")
#undef MACRO
// do what you want
#pragma pop_macro("MACR")
0
ответ дан 27 November 2019 в 04:09
поделиться

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

#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
1
ответ дан 27 November 2019 в 04:09
поделиться

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

2
ответ дан 27 November 2019 в 04:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: