2010-05-10 95 views
6

#define指令的作用是什么?C++中#define指令的用途是什么?

+1

请参阅以下文章中的示例代码,作为* not *使用宏的示例:http://stackoverflow.com/questions/2777774/a-out-termniated-garbage-output-due-砸碎堆栈如何去除这 – 2010-05-10 21:05:01

+1

@Nathan:让我们来看看坏宏的真正来源:http://stackoverflow.com/questions/652788/what-is-the-worst-现实世界中的宏预处理器滥用 - 你已-不断先到对面。 – 2010-05-10 21:50:59

+0

Touche,@David,我只是去了我记忆中最近的一个。你的链接确实包含了一些暴行。 – 2010-05-11 00:18:22

回答

15

#define用于在C和C++中创建宏。您可以在C preprocessor documentation中阅读更多关于它的信息。快速的答案是,它做了几件事情:

  1. 简单的宏 - 基本上只是文本替换。编译时间常数是一个很好的例子:

    #define SOME_CONSTANT 12 
    

    只是替换文本SOME_CONSTANT12无论它出现在你的代码。这种宏通常用于提供代码块的条件编译。例如,有可能是通过与该项目的选项的列表项目中的每个源文件中包含的报头:

    #define OPTION_1 
    #define OPTION_2 
    #undef OPTION_3 
    

    然后在项目代码块将与匹配#ifdef/#endif#块,以使被包裹并在完成的项目中禁用这些选项。使用-D gcc标志会提供类似的行为。然而,对于这种方法是否真的是一种为应用程序提供配置的好方法,有强烈的意见。

  2. 带参数的宏 - 允许您创建可以接受参数并操作它们的“函数式”宏。例如:

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

    将返回参数的平方作为其结果;要小心潜在的操作顺序或副作用问题!下面的例子:

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

    会工作得很好,但这样的:

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

    将调用f()两次,甚至更糟糕:

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

    导致不确定的行为!

    使用一些工具,带参数的宏也可以是variadic,它可以派上用场。

正如评论下文提到,宏的过度使用,或过于复杂或令人困惑宏的发展被认为是不好的风格深受很多 - 一如既往,把可读性,可维护性和可调试代码的上述“聪明'的技术窍门。

+5

+1。由于OP询问了“#define”所扮演的角色,应该强调的是宏不应该被过度使用。 – stakx 2010-05-10 20:57:09

+0

变量宏在C99中是标准的,所以大多数现代工具都应该支持它们。 – pkh 2010-05-10 20:57:21

+1

+1,但应该在几种情况下添加SQUARE()将如何*扩展的示例。 – greyfade 2010-05-10 21:04:50

7

#define(和它相反,#undef)可用于设置编译器指令,然后可以使用#ifndef或#ifdef进行测试。这允许在源文件中定义自定义行为。它通常用于编译不同的环境或调试代码。

一个例子:

#define DEBUG 



#ifdef DEBUG 

//perform debug code 

#endif 
0

ÇC++的#define允许创建预处理器宏。

在正常ÇC++构建过程首先发生的是,预处理器运行时,预处理器看起来虽然源文件的预处理器指令等的#define的#include并且然后执行简单的操作。

如果是#define指令,预处理器执行简单的基于文本的替换。

例如,如果你有代码

#define PI 3.14159f 

float circum = diameter*PI; 

预处理器会变成:通过简单地用相应的文本替换PI的情况下

float circum = diameter* 3.14159; 

。这是一个的#define声明的更先进的用途看看这个article从MSDN

0

inCorrectUseOfHashDefine()

{

的#define的作用是挡板谁继承的人只有最简单的形式与出蓝色陈述你的代码,如:

foreverandever 

因为:

#define foreverandever for(;;) 

}

请偏袒的#define常量。

它也用于设置编译器指令...

+2

为什么-2?它是一个有效的点,我坚持它。 – 2010-05-10 21:12:38

+0

,因为这不是*定义的作用,而是*误用*。 – 2010-05-10 21:14:42

+0

@Rene好吧 - 我已经让我的意图更明确了 – 2010-05-10 21:21:08

1

#define指令有两个常见用途。

第一个是控制编译器如何操作。为此,我们还需要#undef,#ifdef和#ifndef。 (和#endif太...)

您可以通过这种方式制作“编译器逻辑”。一个常见的用途是激活或不是代码的调试部分,这样的:

#ifdef DEBUG 

//debug code here 

#endif 

你将能够例如编译调试代码,通过编写的#define DEBUG

另一个用途这种逻辑的东西,是为了避免双重包括...

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

解决的办法是写:

#ifndef C_FILE_INCLUDED 
#define C_FILE_INCLUDED 

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

#endif 

其他使用#define,是使宏。

最简单的,由简单替代的,如:

#define PI 3.14159265 

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

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

if (1 != 1) { SHOW_ERROR_MESSAGE } 

然后你还可以接受参数的宏,printf的本身通常是一个宏观的,与创建头文件中的#define。

但是这不应该这样做,对于两个重复:首先,速度os宏,与使用内联相同,其次,我们有C++模板,它允许更多地控制函数的变量类型。因此,使用宏与参数的唯一原因,是(通过)的#define是包括警卫会发出奇怪的结构,这将是以后很难理解,像metaprogrammed东西...

+0

哇,我花了我的时间来键入我的帖子,现在看来,我只是复制了两个前任家伙的帖子,并将它们在一个:( – speeder 2010-05-10 21:13:00

2

最常见的用途:

// header.hh 
#ifndef HEADER_HH_ 
#define HEADER_HH_ 

namespace pony { 
// ... 
} 

#endif 

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

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

0

约#define语句大部分事情已经被告知,但目前还不清楚的是C++有大部分的用途更好的替代品:

  1. 的#define定义数字常量可以通过一个const“变量很容易地更换“,作为#define,并不存在于编译的可执行文件中。 AFAIK它可以用于几乎所有可以使用#defined数值常量(包括数组边界)的情况。对我来说,主要优点是这样的常量是明确的类型,所以不需要在宏中添加强制转换,并且是有作用域的,所以它们可以保存在名称空间/类/函数中,而不会污染所有的应用。

 

const int max_array_size=50; 
int an_array[max_array_size]; 
  • 的#define创建宏:宏通常可通过模板被取代;例如,可怕的MAX宏
  •  

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

    ,其中有几个缺点(例如重复参数评价,不可避免内联展开),可通过最大函数所取代

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

    ,它可以是类型安全的(在这个版本中,两个参数被强制为相同的类型),可以以内联方式扩展(不是编译器决定),仅对参数进行一次评估被称为),并且是有作用的。更详细的解释可以参见here

    尽管如此,宏仍必须用于包括警卫,创造某种奇怪的语言扩展,扩展到更多的代码行,有不平衡的圆括号等

    1

    在C++中,有#定义很窄,专门的角色:

    • 头卫兵,在其他的答案
    • 与标准库交互描述。例如,在包含windows.h之前#定义WINDOWS_LEAN_AND_MEAN会关闭像MAX这样经常出现问题的宏。
    • 涉及字符串化(即,打印调试消息的宏)或令牌粘贴的高级宏。

    您应该避免使用#define出于以下目的。原因很多;见例this FAQ entry

    • 编译时常量。改为使用const
    • 简单的宏函数。改用inline函数和模板。