Нужно ли мне #undef локальное #define? Существует ли такая локальная локализация?

Иногда, чтобы упростить запись и чтение, я пишу некоторые локальные макросы #define в функциях (for example, #define O_REAL Ogre::Real).

Нужно ли мне #undef локальный #define, чтобы он оставался в определенном блоке кода? Или это автоматически #undef, когда оно выходит за пределы области видимости? Есть ли у него понятие масштаба?

Я не уверен, как работает #define. Теперь я, конечно, экспериментировал с кодом и делал определенные выводы, но, поскольку я не уверен, мне хотелось бы получить некоторые экспертные заключения/советы.

Ответ 1

#define не относится к области С++. Нет такой вещи, как "локальный" #define. Он будет действовать до тех пор, пока не будет #undef -ed. Механизм макросов препроцессора аналогичен функциям "find-and-replace", найденным в большинстве текстовых редакторов; он не имеет никакого отношения к содержимому файла.

Другими словами, если вы хотите, чтобы ваш #define был локальным в определенном блоке кода, вы должны #undef его в конце этого блока из-за того, что макросы не "понимают" область.

На самом деле, одна из главных причин, почему макросы обескуражены, если они не являются абсолютно необходимыми в С++. Это почему имена макросов обычно печатаются в UPPER_CASE, чтобы указать, что это фактически макрос.


На самом деле существует довольно много макро-решений для вашей конкретной ситуации. Рассмотрим следующее:

namespace ReallyLongOuterNamespace
{
    namespace ReallyLongInnerNamespace
    {
        class Foo {};
        void Bar() {}
    };
}

void DoThis()
{
    // Too much typing!
    ReallyLongOuterNamespace::ReallyLongInnerNamespace::Foo f;
    ReallyLongOuterNamespace::ReallyLongInnerNamespace::Bar();
}

Вы можете использовать псевдонимы пространства имен:

void DoThis()
{
    namespace rlin = ReallyLongOuterNamespace::ReallyLongInnerNamespace;

    rlin::Foo f;
    rlin::Bar();
}

Вы также можете использовать typedef s:

void DoThis()
{
    typedef ReallyLongOuterNamespace::ReallyLongInnerNamespace::Foo MyFoo;

    MyFoo f;
}

Вы также можете использовать объявления using:

void DoThis()
{
    using ReallyLongOuterNamespace::ReallyLongInnerNamespace::Foo;
    using ReallyLongOuterNamespace::ReallyLongInnerNamespace::Bar;

    Foo f;
    Bar();
}

Вы даже можете использовать комбинацию из вышеперечисленного!

void DoThis()
{
    namespace rlin = ReallyLongOuterNamespace::ReallyLongInnerNamespace;
    typedef rlin::Foo MyFoo;
    using rlin::Bar;

    MyFoo f;
    Bar();
}

В отношении Ogre::Real он представляется как typedef для a float или double. Вы все равно можете использовать псевдонимы пространства имен, объявления typedef и using с помощью typedef:

void UseOgre()
{
    typedef Ogre::Real o_Real; // Yes, you can typedef typedefs.
    using Ogre::Real;
    /* Or, you can use:
    namespace o = Ogre;
    typedef o::Real o_Real;
    using o::Real;
    */

    // All equivalent
    Ogre::Real r1;
    o_Real r2;
    Real r3;
    o::Real r4;
}

Ответ 2

Область макроса является частью единицы компиляции, которая появляется после #define, вплоть до конца блока (то есть до конца файла .cpp). Однако Visual С++ имеет пару #pragma push_macro/pop_macro, которая может использоваться в случае совпадения макроопределений. Вы можете нажать предыдущее определение, определить свой собственный, использовать его, и когда вы решите просто поп-предыдущее определение.

Ответ 3

К сожалению, #define не соблюдают правила оценки. #define, которые не являются #undef 'd, будут влиять на весь код после них. Кроме того, если код до того, как вы определите одно и то же имя макроса, у вас возникнут проблемы. В С++ вы обычно можете избежать использования таких локальных макросов с локальными typedefs и ссылками. Например, вы можете сделать:

void foo() {
    typedef Ogre::Real O_REAL;
    // ... 
}

Это будет учитывать правила обзора. Для переменных вы можете использовать ссылки:

void foo() {
    int &BAR = Foo::quux::baz::static_bar;
    // ...
}

Ответ 4

#define обрабатывается препроцессором, который вообще не знает синтаксиса C. Параметр #define игнорирует область действия и останется в силе до тех пор, пока вы не нажмете # или не до конца блока компиляции.

Ответ 5

нет такой вещи, как local define. Определяет всегда предварительное зло; -)

В вашем примере я бы рекомендовал typedef сделать псевдоним для имен переменных

Однако иногда local defines - приятная вещь для программиста (но никогда не для сопровождающего). Чтобы сделать вещи немного проще и немного безопаснее, я всегда undef эти вещи, и я даже защищаю их запись:

#if defined(LOCAL_CROWBAR)
#error Hurgh!
#endif /* LOCAL_CROWBAR */
#define LOCAL_CROWBAR

... use LOCAL_CROWBAR ...

#undef LOCAL_CROWBAR

Тем не менее, избегайте их, когда это возможно!

Ответ 6

Нет. Нет таких вещей, как "local" #define s.

Область, в которой помещается #define, пока неизвестна, поскольку они обрабатываются препроцессором. (Следовательно, вы иногда слышите термин "директива препроцессора", а не просто "макрос".)