关于c预处理器:C ++中#define指令的目的是什么?

What is the purpose of the #define directive in C++?

#define指令的作用是什么?


用於在C和C+中创建宏。你可以在C预备文件中更多地阅读。快捷的答案是它有一些东西:

  • 简单的宏-基本的只是替换文本。Compile time constants are a good example:

    1
    #define SOME_CONSTANT 12

    简单地用12代替SOME_CONSTANT文本,当它出现在您的代码中。这个宏的输出通常用于提供码块的条件编译。For example,there might be a header included by each source file in a project with a list of options for the project:

    ZZU1

    然后,项目中的代码块将与EDOCX1〕〔3〕匹配,以使这些选项在最后的项目中得以实现和无法实现。法国国旗将提供类似的行为。有强烈的观点,无论是在哪一个方法实际上是一个很好的方法来提供一个应用程序的配置。

  • 具有参数的宏-允许您设定函数-像可以引用参数并操纵它们的宏。For example:

    1
    #define SQUARE(x)  ((x) * (x))

    论据的广场作为其结果是否会回复;注意潜在的操作顺序或侧面效应问题!The following example:

    1
    int x = SQUARE(3);     // becomes int x = ((3) * (3));

    Will works fine,but something like:

    1
    int y = SQUARE(f());   // becomes int y = ((f()) * (f()));

    Will call f()twice,or even worse:

    1
    int z = SQUARE(x++);   // becomes int z = ((x++) * (x++));

    结果在未知行为中!

    有了一些工具,具有参数的宏也可以变异,可以手工来。

  • 如在评注中指出,过度使用宏,或过度复杂或混淆宏的发展被许多人视为坏风格——例如,在许多情况下,将可行性、持续性和解读你的代码放在清除技术错误上。


    Define(and it's opposite, 35;undef)can be used to set compiler directives which can be tested against using 355;IFNDEF or 355;IFDEF.本发明允许在源文件中定义自定义行为。这通常是为不同的环境或债务代码编纂的。

    An example:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #define DEBUG



    #ifdef DEBUG

    //perform debug code

    #endif


    #define的最常见用途(到目前为止)是包括警卫:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // header.hh
    #ifndef HEADER_HH_
    #define HEADER_HH_

    namespace pony {
    // ...
    }

    #endif

    #define的另一个常见用法是创建一个配置文件,通常是config.h文件,在该文件中,我们基于各种状态和条件#define宏。然后,在我们的代码中,我们使用#ifdef#elif defined()等测试这些宏,以支持不同情况下的不同编译。这不像include-guard习惯用法那样可靠,您需要在这里小心,因为如果分支错误,那么您可能会得到非常模糊的编译器错误,或者更糟的是,运行时行为。

    一般来说,除了包含保护之外,您需要仔细考虑(最好是两次)这个问题,看看是否可以使用编译器而不是预处理器来解决问题。编译器比预处理器更聪明。不仅如此,编译器也不可能混淆预处理器,而预处理器无疑会混淆和误导编译器。


    在C++中,γ定义具有非常狭窄的专门角色:

    • 其他答案中描述的收割台防护装置
    • 与标准库交互。例如,定义窗口"lean"和"u"意味着在包含windows.h之前,关闭某些经常有问题的宏,如max。
    • 涉及字符串化(即打印调试消息的宏)或标记粘贴的高级宏。

    您应该避免为以下目的使用define。原因很多;请参阅Instace this faq entry。

    • 编译时间常量。用const代替。
    • 简单宏函数。使用inline函数和模板。

    定义指令有两个共同的用途。

    第一个是控制编译器的行为。要做到这一点,我们还需要undef、ifdef和ifndef。(还有结尾也是…)

    你可以这样做"编译器逻辑"。常见的用法是激活或不激活代码的调试部分,如:

    1
    2
    3
    4
    5
    #ifdef DEBUG

    //debug code here

    #endif

    例如,您可以通过编写定义调试来编译调试代码。

    这种逻辑的另一种用法是避免双重包含…

    例如,文件A包括文件B和C。但文件B也包括C。这可能会导致编译错误,因为"C"存在两次。

    解决方案是写:

    1
    2
    3
    4
    5
    6
    #ifndef C_FILE_INCLUDED
    #define C_FILE_INCLUDED

    //the contents of header"c" go here.

    #endif

    定义的另一个用途是生成宏。

    最简单的一个由简单的替换组成,例如:

    1
    2
    3
    4
    5
    #define PI 3.14159265

    float perimeter(float radius) {
        return radius*2*PI;
    }

    1
    2
    3
    #define SHOW_ERROR_MESSAGE printf("An serious error happened");

    if ( 1 != 1 ) { SHOW_ERROR_MESSAGE }

    然后您还可以生成接受参数的宏,printf本身通常是一个宏,在头文件中用define创建。

    但这不应该做,因为有两个原因:首先,速度OS宏与使用内联是相同的,第二,我们有C++模板,它允许对具有可变类型的函数进行更多的控制。所以,使用带参数的宏的唯一原因是构造奇怪的结构,这在以后很难理解,就像元编程的东西…


    关于定义的大部分事情已经被告知了,但是目前还不清楚C++对于它们的大部分使用有更好的替代:

  • #定义以定义数值常量可以很容易地用常量"变量"替换,而这个变量作为定义并不存在于编译的可执行文件中。Afaik可以用于几乎所有可以使用定义的数值常量(包括数组边界)的情况。对我来说,这些常量的主要优点是类型清晰,所以不需要在宏中添加强制转换"只是为了确定",并且是范围的,因此它们可以保存在名称空间/类/函数中,而不会污染所有应用程序。
  • nbsp;

    1
    2
    const int max_array_size=50;
    int an_array[max_array_size];

  • #定义以创建宏:宏通常可以替换为模板;例如,可怕的max宏
  • nbsp;

    1
    #define MAX(a,b)    ((a)<(b)?(b):(a))

    它有几个缺点(例如重复参数评估、不可避免的内联扩展),可以用max函数替换

    1
    2
    3
    4
    template<typename T> T & max(T & a, T & b)
    {
        return a<b?b:a;
    }

    它可以是类型安全的(在这个版本中,两个参数被强制为同一类型),可以是内联的也可以是非内联的(这是编译器的决定),只计算一次参数(当调用它时),并且是作用域。这里可以找到更详细的解释。

    尽管如此,宏仍然必须用于包含保护、创建某种奇怪的语言扩展,扩展到更多的代码行、具有不平衡的括号等。


    不正确

    ……

    The role of 35;define is to baffle people who inherit your code with out of the blue statements like:

    1
    foreverandever

    Because of:

    1
    #define foreverandever for(;;)

    请致电常数超过35。

    IT also for setting compiler directives…


    在C或C+++++++35中,定义允许您创建宏。

    在正常C或C++++++建造过程中,发生的第一件事是预处理器运行,预处理器认为,源文件为预处理器指令如 355;define或 355;包括和随后的简单操作。

    在一个 35的案例中,Define Directive the Preprocessor does simple text based substitution.

    以你有密码为例

    1
    2
    3
    #define PI 3.14159f

    float circum = diameter*PI;

    The preprocessor would turn it into:

    1
    float circum = diameter* 3.14159;

    通过简单地将PI的实例与相应的文本重叠。这仅仅是一个简单的形式,定义声明更多的高级使用从MSDN检查此文章。