在宏中过度使用会损害性能吗?
Posted
技术标签:
【中文标题】在宏中过度使用会损害性能吗?【英文标题】:can overuse in Macros hurt performance? 【发布时间】:2014-03-20 20:47:15 【问题描述】:我有一个很长的代码,它被调用了数百万次, 我注意到,如果我将所有宏更改为内联函数,代码运行速度会快很多。
你能解释这是为什么吗?宏不只是文本替换吗?与可以调用函数的内联函数相反?
【问题讨论】:
类似于#define MAX(x, y) ((x) > (y) ? (x) : (y))
,它会多次评估其参数。
宏只是文本替换。要查看您的编译器对它们做了什么,请使用 -E
标志进行编译,例如 g++ -E file.cpp
MAX(expensivecall(), otherexpensivecall())
将执行其中一个昂贵的调用两次。使用多个宏,错误会变得更糟。
如果使用 C++,请不要使用宏。内联函数会更好
@androidy - 编译器理解语言的语义。预处理器没有。因此编译器在优化时可以有更好的 bash
【参考方案1】:
宏是一种文本替换,因此通常会生成更多可执行代码。每次调用宏时,都会插入代码(好吧,不一定,宏可能是空的......但原则上)。 另一方面,内联函数可能与宏的工作方式相同,但它们也可能根本不是内联的。
一般来说,inline
关键字是一个弱提示,而不是一个要求,编译器现在将基于启发式,主要是伪指令的数量明智地内联函数(或将放弃这样做)。
因此,内联函数可能会导致编译器不内联该函数,或者内联几次,然后再将其称为非内联函数。 令人惊讶的是,不内联实际上可能比内联更快,因为它减少了整体代码大小,从而减少了缓存和 TLB 未命中的数量。
【讨论】:
【参考方案2】:这取决于您使用的特定宏和函数调用。一个特定的宏实际上可以编译成比内联函数更长的操作集。通常最好不要对某些进程使用宏。内联函数将允许编译器进行类型检查和优化各种过程。宏会出现许多错误,实际上会导致各种低效率(例如必须将变量移入和移出存储)。
无论如何,由于您在代码中确实看到了这种情况,您可以看出编译器能够优化您的内联代码,而不是盲目地放入文本扩展中。
请注意,谷歌搜索“宏与内联”显示了许多关于此的讨论。
【讨论】:
我读了大部分。他们没有为宏性能变差提供很好的例子。就像错误的输出以及为什么内联更好之类的东西 @Gilad 就个人而言,我会设置预处理器选项和编译器选项来扩展代码区域,以查看宏和内联版本的不同之处。我也可能会告诉它为一小段(甚至最少)代码生成程序集,以查看优化在做什么。我也会尝试不同级别的优化,看看发生了什么。您还可以在问题中显示实际的宏和内联代码。【参考方案3】:除了强制内联之外,如果没有仔细编写宏以不对参数进行两次评估,宏也会对速度产生不利影响。以这个类似函数的小宏及其等效的内联函数为例:
#define square(x) ((x)*(x))
inline long square(long x) return x*x;
现在,当您使用变量square(foo)
调用它们时,它们是等价的。宏版本扩展为((foo)*(foo))
,这是一个乘法,就像内联函数一样。
但是,如果您使用square(expensiveComputation(foo))
调用它们,则宏的结果是,expensiveComputation()
被调用了两次。相比之下,内联函数的行为类似于任何函数:它的参数在函数体执行之前被计算一次。
当然,您可以使用复合语句的 gnu 扩展来编写宏(请参阅http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html 以获取相关文档)以避免像这样的双重评估:
#define square(x) ( \
long square_temp_variable = (x); \
square_temp_variable*square_temp_variable; \
)
但这很麻烦,而且代码不可移植。所以,最好坚持使用内联函数。
【讨论】:
不仅如此,在宏范围内创建局部变量 square_temp_variable 也会导致处理速度变慢。它可能是最小的,但超过数百万次,它可以加起来 @sabbahillel 这不是真的,与内联函数调用相比,定义新的局部变量没有开销。请记住,函数调用将为所有函数参数创建变量。即使编译器内联调用,生成的代码也必须就像这些变量被创建一样。当然,复制省略是允许的,但如果您在宏中创建局部变量也是如此。【参考方案4】:一般来说,尽可能用内联函数替换函数样式宏是一个很好的建议。
您不仅摆脱了一些讨厌的陷阱a = MIN(i++, 50)
,例如,您还获得了类型安全性,并且正如在某些 cmets 中所述,您避免了对争论的多次评估,这可能对性能产生非常糟糕的影响。
【讨论】:
我真的觉得这不能很好地回答这个问题。 OP 想知道 为什么 宏会导致更差的性能,但是你给了他各种其他(不相关的)反对使用宏的论据,并且非常简短地提到了对参数的多重评估(没有任何详细说明),这已经在评论中得到了更好的处理。通过删除不相关的内容并扩展性能解释,可以改进答案。以上是关于在宏中过度使用会损害性能吗?的主要内容,如果未能解决你的问题,请参考以下文章