何时以及为何使用#define宏(x)代替函数?

时间:2014-12-21 19:03:31

标签: c++ c macros

看到this question让我想知道为什么这个方法(玩具示例):

#define foo(x) bar[x] = 0

将优先于该功能:

void foo(unsigned x){ bar[x] = 0; }

在上面链接的问题之前,我之前只在PolarSSL库中看过这个,我认为它是某种优化,并试图不要过多考虑它。

我假设使用预处理器宏将'call'替换为它所存在的'(not-)函数体';而void函数可能会或可能不会被编译器优化,因此可能会导致大量分支操作或一两个简单的操作。

还有其他好处吗?

何时首选宏方法,何时更好地信任编译器?

3 个答案:

答案 0 :(得分:6)

定义宏只是为了使代码更快是没用的。一个好的编译器将内联 功能调用。但是,当您需要将结果用作常量时,宏可能很有用。

#define ENCODED(a,b,c,d) (((((((a)<<8)+b)<<8)+c)<<8)+d)

switch (a) {
   case ENCODED('f','o','o','0'):   ...
   case ENCODED('b', 'a', 'r', '1'): ...
}

如果要定义新标识符:

#define LIB_VERSION v101
#define VERSIONNED(x) x##LIB_VERSION

void VERSIONNED(myfunction)(int x) { ... }

当你想做一些其他的“魔法”时,例如:

#define assert(x) {if ((x) == 0) {printf("%s:%d: Assertion %s failed\n", __FILE__, __LINE__, #x); exit(-1); }}

如果要定义使用多种类型的“通用”函数。仅仅是为了说明:

#define DELETE_LAST_ITEM(x) {while (x->next->next != NULL) x=x->next ; x->next = NULL}

可能还有其他一些我现在还不记得的情况。

答案 1 :(得分:5)

首先,我希望您的宏实际上是:

#define foo(x) do { bar[x] = 0; } while (0)

正确的semicolon swallowing

支持宏的一点是因为您认为编译器的优化器不够好。你可能错了。但是如果你真的仔细查看输出并知道你在做什么,那么你可能是对的,这就是它在Linux内核中经常使用的原因。

另一个原因是宏是无类型的,所以你可以这样做:

#define foo(x,t) do { t[x] = 0; } while (0)

适用于任何类型t。缺乏类型检查通常是一个缺点,但在定义您想要使用任何类型的内容时它会很有用。

答案 2 :(得分:4)

  

还有其他好处吗?

使用宏观的好处很少。举个例子,您可以使用__LINE____FILE__来查看调用此宏的位置。

#define foo(x) bar[x] = 0; PrintFunction("...", __FILE__,__LINE__)

宏永远不会给你更强大的类型检查功能。

  

何时首选宏方法,何时更好地信任编译器?

因此,只有当您没有任何选择才能使用函数时,Macro应该是首选,因为大多数情况下您可以信任编译器优化器。