在C++中执行宏可以提高性能
Do macros in C++ improve performance?
我是C++的初学者,刚刚读到宏的工作原理是随时替换文本。在这种情况下,这是否意味着它使.exe运行得更快?这与内联函数有何不同?
例如,如果我有以下宏:
#define SQUARE(x) ((x) * (x))
和正常功能:
int Square(const int& x)
{
return x*x;
}
和内联功能:
inline int Square(const int& x)
{
return x*x;
}
这三者之间的主要区别是什么,尤其是内联函数和宏之间的区别?非常感谢。
如果可能的话,应该避免使用宏。内联函数总是更好的选择,因为它们是类型安全的。内联函数应该和宏一样快(如果它确实是由编译器内联的;请注意,inline
关键字不是绑定的,只是对编译器的提示,如果无法内联,编译器可能会忽略它)。
PS:就风格而言,对于基本的参数类型,如int
或double
,应避免使用const Type&
。简单地使用类型本身,换句话说,使用
int Square(int x)
由于副本不会影响(甚至使性能变差)性能,请参阅例如此问题以了解更多详细信息。
宏翻译为:用模式B愚蠢地替换模式A。这意味着:一切都发生在编译器启动之前。有时它们会派上用场;但总的来说,它们应该避免。因为你可以做很多事情,以后在调试器中,你不知道发生了什么
此外:你的表演方式很好,很天真,可以说是友好的。首先你要学习这门语言(对于现代C++来说,这很难,因为有很多重要的概念和事情需要你去了解和理解)。然后你练习,练习,练习。然后,当您的现有应用程序出现性能问题时;然后进行分析以了解真正的问题。
换言之:如果你对表演感兴趣,那么你问错了问题。你应该更多地担心架构(比如:潜在的瓶颈)、配置(系统中不同节点之间的延迟)等等。当然,你应该运用常识;并且不写明显浪费存储器或CPU周期的代码。但有时一段运行速度慢50%的代码。。。阅读和维护起来可能容易500%。如果执行时间是500ms,而不是250ms;这可能是完全可以的(除非那个特定的部分每分钟被调用一千次)。
在没有优化标志的编译器(clang++)上,平方函数不会内联。它生成的代码看起来像这个
4009f0: 55 push %rbp
4009f1: 48 89 e5 mov %rsp,%rbp
4009f4: 89 7d fc mov %edi,-0x4(%rbp)
4009f7: 8b 7d fc mov -0x4(%rbp),%edi
4009fa: 0f af 7d fc imul -0x4(%rbp),%edi
4009fe: 89 f8 mov %edi,%eax
400a00: 5d pop %rbp
400a01: c3 retq
imul是执行工作的汇编指令,其余的是四处移动数据。调用它的代码看起来像
400969: e8 82 00 00 00 callq 4009f0 <_Z6squarei>
iI将-O3标志添加到内联中,该imul显示在C++代码中调用该函数的主函数中
0000000000400a10 <main>:
400a10: 41 56 push %r14
400a12: 53 push %rbx
400a13: 50 push %rax
400a14: 48 8b 7e 08 mov 0x8(%rsi),%rdi
400a18: 31 f6 xor %esi,%esi
400a1a: ba 0a 00 00 00 mov $0xa,%edx
400a1f: e8 9c fe ff ff callq 4008c0 <strtol@plt>
400a24: 48 89 c3 mov %rax,%rbx
400a27: 0f af db imul %ebx,%ebx
这是一件合理的事情,为您的机器获得汇编语言的基本处理,并在源代码上使用gcc-s,或在二进制文件上使用objdump-D(就像我在这里所做的那样)来查看到底发生了什么
使用宏而不是内联函数可以得到非常类似的
0000000000400a10 <main>:
400a10: 41 56 push %r14
400a12: 53 push %rbx
400a13: 50 push %rax
400a14: 48 8b 7e 08 mov 0x8(%rsi),%rdi
400a18: 31 f6 xor %esi,%esi
400a1a: ba 0a 00 00 00 mov $0xa,%edx
400a1f: e8 9c fe ff ff callq 4008c0 <strtol@plt>
400a24: 48 89 c3 mov %rax,%rbx
400a27: 0f af db imul %ebx,%ebx
请注意宏的许多危险之一:它的作用是什么?
x = 5; std::cout << SQUARE(++x) << std::endl;
36?没有,42。它变成
std::cout << ++x * ++x << std::endl;
变成6*7
不要因为别人告诉你不要关心优化而拖延。使用C或C++作为语言本身就是一种优化。试着弄清楚你是否在浪费时间,并且要理智。
宏只是执行文本替换来修改源代码。
因此,宏本身并不会影响代码的性能。用于设计和编码的技术显然会影响性能。因此,宏对性能的唯一影响是基于宏的作用(即编写宏要发出的代码)。
宏的最大危险在于它们不尊重范围。他们所做的改变是无条件的、跨职能的,诸如此类。编写宏时有很多微妙之处,可以使它们按预期运行(避免代码中意外的副作用,避免未定义的行为等)。这意味着使用宏的代码更难理解,也更难理解。
在最好的情况下,使用现代编译器,使用宏可以获得与内联函数相同的性能增益,但代价是增加代码错误行为的可能性。因此,您最好使用内联函数——与宏不同,它们是类型安全的,并且与其他代码一致工作。
现代编译器可能会选择不内联函数,即使您已将其指定为内联函数。如果发生这种情况,您通常不需要担心——在决定是否应该内联函数方面,现代编译器能够比大多数现代程序员做得更好。
只有当其参数本身是#defined常量时,使用这样的宏才有意义,因为计算将由预处理器执行。即便如此,也要仔细检查结果是否符合预期。
在处理经典变量时,(内联)函数形式应首选为:
- 它是类型安全的
- 它将以一致的方式处理用作参数的表达式。这不仅包括Peter引用的每/后增量的情况,而且当参数本身是计算密集型表达式时,使用宏形式强制对该参数求值两次(可能不一定求值为相同的值btw),而函数只求值一次
我不得不承认,我曾经为简单函数的快速原型设计编写过这样的宏,但这些年来让我失去的时间最终改变了我的想法!
- 从 16UC3 到 8UC3 的高性能 OpenCV 矩阵转换
- 如何从高性能的输入迭代器返回变体?
- 编写高性能C++二传手
- 提升图形库:以高性能的方式检查vertex_descriptor的有效性
- 高性能程序,什么是更好的矢量数组或矢量的矢量
- 如何在不使用函数或类的情况下重复代码段,以便在C++中实现高性能循环
- 标准::矢量的高性能替代品
- 在Qt中以高性能方式将(富)文本附加到QTextEdit或QTextBrowser中
- 在字典中查找单词模式,高性能
- 关于学习C++编码以实现高效/高性能数学例程,有哪些(推荐的)资源/书籍
- C++ 使用Google Mock进行高性能单元测试
- 使用 winAPI 设置窗口的高性能电源计划C++
- C++组合高性能函数
- 实现类似于Qt的高性能互斥锁
- 用于高性能加法和乘法的常量形式
- 哪个字符串类在c++中使用高性能和简单
- 什么是窗口高性能计数器的分辨率
- C++ 中的高性能代码(继承、指向函数的指针、if)
- 非虚拟接口?(需要一个非常高性能的低级抽象)
- 如何在特征中实现高性能分段线性传递函数