Do I need to #undef a local #define? Is there such a thing as a local define?

后端 未结 6 1069
刺人心
刺人心 2021-02-05 12:45

Sometimes to make things easier to write and read, I write some local #define macros within functions (for example, #define O_REAL Ogre::Real).

相关标签:
6条回答
  • 2021-02-05 12:58

    The scope of a macro is part of compilation unit that comes after #define, up until the end of the unit (which is to say, until the end of .cpp file). However Visual C++ has a pair of #pragma push_macro/pop_macro that can be used in a case where macro definitions overlap. You can push previous definition, define your own, use it, and when you decide just pop previous definition.

    0 讨论(0)
  • 2021-02-05 12:59

    Unfortunately, #defines do not respect scoping rules. #defines that are not #undef'd will affect all code after them. Additionally, if code before you defines the same macro name, you'll have problems. In C++ you can usually avoid needing to use such local macros with local typedefs and references. For example, you could do:

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

    This will respect scoping rules. For variables you can use references:

    void foo() {
        int &BAR = Foo::quux::baz::static_bar;
        // ...
    }
    
    0 讨论(0)
  • 2021-02-05 13:09

    there is no such thing as a local define. Defines are always tentative evil ;-)

    For your example I would recommend typedef to make alias for variable names

    However, sometimes local defines are a nice thing for the programmer (but the are never for the maintainer). To make things a bit easier and a bit safer I always undef these things and I even guard their entry:

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

    Nevertheless, avoid those whenever possible!

    0 讨论(0)
  • 2021-02-05 13:11

    #define does not respect any C++ scope. There is no such thing as a "local" #define. It'll be in effect until it is #undef-ed. The preprocessor's macro mechanism is just like the "find-and-replace" functionality found in most text editors; it has no respect for the contents of the file.

    In other words, if you want your #define to be local within a certain block of code, you must #undef it at the end of that block due to the fact that macros do not "understand" scope.

    In fact, that's one of the biggest reasons why macros are discouraged unless they are absolutely necessary in C++. It's why macro names are usually typed in UPPER_CASE to indicate that it's in fact a macro.


    There are actually quite a few macro-less solutions for your specific situation. Consider the following:

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

    You can use namespace aliases:

    void DoThis()
    {
        namespace rlin = ReallyLongOuterNamespace::ReallyLongInnerNamespace;
    
        rlin::Foo f;
        rlin::Bar();
    }
    

    You can also use typedefs:

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

    You can also use using declarations:

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

    You can even use a combination of the above!

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

    With respect to Ogre::Real, it appears to be a typedef for a float or a double. You can still use namespace aliases, typedefs and using declarations with typedefs as well:

    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;
    }
    
    0 讨论(0)
  • 2021-02-05 13:15

    No. There are no such things as "local" #defines.

    The scope in which the #define is placed, is unknown at the time as they are processed by the - well - preprocessor. (Hence you sometimes hear the term "preprocessor directive" instead of just "macro".)

    0 讨论(0)
  • 2021-02-05 13:22

    #define is handled by the preprocessor, which doesn't actually know C syntax at all. A #define ignores scope, and will remain in effect until you #undef it or until the end of the compilation unit.

    0 讨论(0)
提交回复
热议问题