宏和内联函数的区别在于宏是在编译器看到之前处理的。
在没有优化标志的编译器 (clang++) 上,square 函数不会被内联。它生成的代码是这样的
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>
我将 -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++ 作为您的语言本身就是一种优化。如果您在浪费时间,请尝试解决并保持理智。