【问题标题】:Do I need to #undef a local #define? Is there such a thing as a local define?我需要#undef 本地#define 吗?有本地定义这样的东西吗?
【发布时间】:2011-02-20 09:04:27
【问题描述】:

有时为了更易于编写和阅读,我在函数(for example, #define O_REAL Ogre::Real) 中编写了一些本地#define 宏。

我是否需要#undef 本地 #define 以确保它保持在某个代码块内?或者当它超出范围时它会自动#undef?它甚至有范围的概念吗?

我不确定 #define 在这种情况下是如何工作的。现在,我当然已经对代码进行了实验并得出了某些结论,但由于我不确定,我希望得到一些专家的意见/建议。

【问题讨论】:

    标签: c++ c-preprocessor


    【解决方案1】:

    #define 不尊重任何 C++ 范围。没有“本地”#define 这样的东西。它将在#undef-ed 之前一直有效。预处理器的宏机制就像大多数文本编辑器中的“查找和替换”功能一样;它不尊重文件的内容。

    换句话说,如果您希望您的#define 在某个代码块中是本地的,您必须在该代码块的末尾#undef 它,因为宏不“理解”范围。

    事实上,这是不鼓励使用宏的最大原因之一,除非它们在 C++ 中是绝对必要的。这就是为什么宏名称通常输入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();
    }
    

    你也可以使用typedefs:

    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 对应floatdouble。您仍然可以使用命名空间别名、typedefs 和 using 声明以及 typedefs:

    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 C++ 有一对#pragma push_macro/pop_macro,可以在宏定义重叠的情况下使用。您可以推送之前的定义,定义自己的定义,使用它,当您决定时只需弹出之前的定义。

      【讨论】:

        【解决方案3】:

        很遗憾,#defines 不遵守范围规则。 #defines 不是 #undef'd 将影响它们之后的所有代码。此外,如果您之前的代码定义了相同的宏名称,您将遇到问题。在 C++ 中,您通常可以避免将此类本地宏与本地 typedefs 和引用一起使用。例如,您可以这样做:

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

        遵守范围规则。对于变量,您可以使用引用:

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

        【讨论】:

          【解决方案4】:

          #define 由预处理器处理,它实际上根本不知道 C 语法。 #define 忽略范围,并且将一直有效,直到您 #undef 它或直到编译单元结束。

          【讨论】:

            【解决方案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】:

              没有。没有“本地”#defines 之类的东西。

              #define 所在的范围在当时是未知的,因为它们是由-well-预处理器处理的。 (因此您有时会听到术语“预处理器指令”而不仅仅是“宏”。)

              【讨论】:

                猜你喜欢
                • 2013-05-02
                • 1970-01-01
                • 2014-09-16
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多