#define
指令的作用是什么?#define
指令的作用是什么?#define
用于在 C 和 C++ 中创建宏。您可以在C预处理器文档中了解更多信息。快速回答是,它可以做以下几件事情:
简单宏 - 基本上只是文本替换。 编译时常量是一个很好的例子:
#define SOME_CONSTANT 12
这个宏会在你的代码中所有出现 SOME_CONSTANT
的地方都替换成 12
。这种宏通常用于提供代码块的条件编译。例如,一个项目中每个源文件都包含一个选项列表的头文件:
#define OPTION_1
#define OPTION_2
#undef OPTION_3
然后项目中的代码块将被包含在匹配的#ifdef
/#endif#
块中,以在完成的项目中启用或禁用这些选项。使用-D
gcc标志将提供类似的行为。对于是否使用这种方法来提供应用程序配置,存在强烈的意见分歧。
带参数的宏 - 允许您创建可以接收参数并操纵它们的“函数式”宏。例如:
#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++));
结果会导致未定义的行为!
使用某些工具,带有参数的宏也可以是可变参数的,这可能很方便。
正如下面评论中所提到的,滥用宏或开发过于复杂或令人困惑的宏被许多人认为是不好的风格 - 像往常一样,将代码的可读性、可维护性和可调试性置于“聪明”的技术技巧之上。
#ifdef
... #endif
)。在 C++ 中,最好使用常量来实现 1),并使用模板来实现 2)。 - AshleysBrain#define(以及它的相反,#undef)可用于设置编译器指令,然后可以使用#ifndef或#ifdef进行测试。这允许在源文件中定义自定义行为。通常用于编译不同环境或调试代码。
一个示例:
#define DEBUG
#ifdef DEBUG
//perform debug code
#endif
#define
最常用(远超其他用途)的是用于包含保护:
// header.hh
#ifndef HEADER_HH_
#define HEADER_HH_
namespace pony {
// ...
}
#endif
#define
的方法是创建配置文件,通常是config.h文件,在其中根据各种状态和条件#define
宏。然后,在我们的代码中,我们使用#ifdef
,#elif defined()
等测试这些宏,以支持不同情况下的不同编译。这不如include-guard惯用语法坚固,您需要小心,因为如果分支错误,则可能会出现非常晦涩的编译器错误,或者更糟糕的是运行时行为。#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 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创建。
但是这样做有两个原因:首先,宏的速度与使用内联相同,其次,我们有c++模板,允许更多地控制带有变量类型的函数。因此,使用带有参数的宏的唯一原因是创建奇怪的结构,这些结构以后会很难理解,例如元编程的东西...
C++中,#define有非常狭窄、专门的作用:
以下情况应避免使用#define。原因很多,请参见this FAQ entry。
const
。inline
函数和模板。在C或C++中,#define允许您创建预处理器宏。
在正常的C或C++构建过程中,首先发生的事情是预处理器运行,预处理器查找源文件中的预处理指令,如#define或#include,然后执行简单的操作。
对于#define指令,预处理器执行基于文本的简单替换。
例如,如果您有以下代码:
#define PI 3.14159f
float circum = diameter*PI;
预处理器将把它转换为:
float circum = diameter* 3.14159;
通过简单地将PI的实例替换为相应的文本即可完成。这只是一个#define语句的最简形式,更高级的用法请查看MSDN的文章。
inCorrectUseOfHashDefine()
{
#define 的作用是让继承你代码的人感到困惑,因为会出现一些突然的语句。
foreverandever
由于:
#define foreverandever for(;;)
}
请优先使用常量而不是 #define。#defines 的大部分内容已经被讲述过了,但是并不清楚的是 C++ 有更好的替代品来满足它们的大多数用途:
const int max_array_size=50;
int an_array[max_array_size];
#define MAX(a,b) ((a)<(b)?(b):(a))
标签,存在一些缺点(例如重复参数评估,不可避免的内联扩展),可以被最大函数所替代。
template<typename T> T & max(T & a, T & b)
{
return a<b?b:a;
}
这个函数可以保证类型安全(在这个版本中,两个参数强制为相同的类型),可以内联扩展或不扩展(由编译器决定),在调用时只评估一次参数,并且有范围。可以在这里找到更详细的解释。
然而,宏仍然必须用于包含保护,以创建某种奇怪的语言扩展,它们扩展为更多代码行,具有无法平衡的括号等。