#define
指令的作用是什么?
答案 0 :(得分:14)
#define
用于在C和C ++中创建宏。您可以在C preprocessor documentation中详细了解相关信息。快速回答是它做了一些事情:
简单宏 - 基本上只是文本替换。编译时间常数就是一个很好的例子:
#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++));
导致未定义的行为!
使用某些工具,带参数的宏也可以是variadic,这可以派上用场。
正如下面评论中所提到的,过度使用宏,或过度复杂或令人困惑的宏的开发被许多人认为是不好的风格 - 一如既往,将代码的可读性,可维护性和可调试性置于'聪明'技术诀窍之上
答案 1 :(得分:7)
#define(相反,它是#undef)可用于设置编译器指令,然后可以使用#ifndef或#ifdef对其进行测试。这允许在源文件中定义自定义行为。它通常用于编译不同的环境或调试代码。
一个例子:
#define DEBUG
#ifdef DEBUG
//perform debug code
#endif
答案 2 :(得分:2)
#define
最常见的用途(远)适用于包含警员:
// header.hh
#ifndef HEADER_HH_
#define HEADER_HH_
namespace pony {
// ...
}
#endif
#define
的另一个常见用途是创建配置文件,通常是config.h文件,其中我们#define
宏基于各种状态和条件。然后,在我们的代码中,我们使用#ifdef
,#elif defined()
等来测试这些宏,以支持针对不同情况的不同编译。这不像include-guard惯用法那么坚固,你需要在这里小心,因为如果分支错误,那么你可以得到非常模糊的编译器错误,或者更糟糕的是,运行时行为。
通常,除了包含保护之外,您需要仔细考虑(最好两次)关于问题,并查看是否可以使用编译器而不是预处理器来解决它。编译器比预处理器更聪明。不仅如此,编译器不可能混淆预处理器,而预处理器肯定会混淆和误导编译器。
答案 3 :(得分: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 ++模板,允许更多地控制变量类型的函数。因此,使用带参数的宏的唯一原因是制作奇怪的结构,以后很难理解,就像元编程的东西......
答案 4 :(得分:1)
在C ++中,#define具有非常狭窄的专业角色:
您应避免使用#define用于以下目的。原因很多;见instace this FAQ entry。
const
。inline
函数和模板。答案 5 :(得分:0)
允许您创建预处理器宏。
在正常的 C 或 C ++ 构建过程中,首先发生的事情是PreProcessor运行,预处理器查看预处理器指令的源文件,如 #define 或 #include ,然后使用它们执行简单的操作。
在 #define 指令的情况下,预处理器执行简单的基于文本的替换。
例如,如果你有代码
#define PI 3.14159f
float circum = diameter*PI;
预处理器会把它变成:
float circum = diameter* 3.14159;
只需将PI的实例替换为相应的文本即可。对于更高级的用途,这只是 #define 语句的最简单形式,请从MSDN中查看此article
答案 6 :(得分:0)
inCorrectUseOfHashDefine()
{
#define的作用是阻止那些使用以下蓝色语句继承你代码的人:
foreverandever
因为:
#define foreverandever for(;;)
}
请优先选择常规#define。
它还用于设置编译器指令......
答案 7 :(得分:0)
关于#defines的大部分内容已经被告知,但目前尚不清楚C ++在大多数用途中有更好的替代品:
const int max_array_size=50;
int an_array[max_array_size];
#define MAX(a,b) ((a)<(b)?(b):(a))
,有几个缺点(例如重复参数评估,不可避免的内联扩展),可以用max函数替换
template<typename T> T & max(T & a, T & b)
{
return a<b?b:a;
}
可以是类型安全的(在这个版本中,两个参数被强制为相同的类型),可以内联扩展,也可以不扩展(它是编译器决定),只评估一次参数(当它被调用时) ,并且是范围的。可以找到更详细的解释here。
尽管如此,宏还必须用于包含保护,以创建某种奇怪的语言扩展,扩展到更多代码行,具有不平衡的括号等。