运行以下代码:
案例1:
#include <stdio.h>
int count=0;
void g(void){
printf("Called g, count=%d.\n",count);
}
#define EXEC_BUMP(func) (func(),++count)
typedef void(*exec_func)(void);
inline void exec_bump(exec_func f){
f();
++count;
}
int main(void)
{
//int count=0;
while(count++<10){
EXEC_BUMP(g);
//exec_bump(g);
}
return 0;
}
案例2:
#include <stdio.h>
int count=0;
void g(void){
printf("Called g, count=%d.\n",count);
}
#define EXEC_BUMP(func) (func(),++count)
typedef void(*exec_func)(void);
inline void exec_bump(exec_func f){
f();
++count;
}
int main(void)
{
//int count=0;
while(count++<10){
//EXEC_BUMP(g);
exec_bump(g);
}
return 0;
}
案例3:
#include <stdio.h>
int count=0;
void g(void){
printf("Called g, count=%d.\n",count);
}
#define EXEC_BUMP(func) (func(),++count)
typedef void(*exec_func)(void);
inline void exec_bump(exec_func f){
f();
++count;
}
int main(void)
{
int count=0;
while(count++<10){
//EXEC_BUMP(g);
exec_bump(g);
}
return 0;
}
案例4:
#include <stdio.h>
int count=0;
void g(void){
printf("Called g, count=%d.\n",count);
}
#define EXEC_BUMP(func) (func(),++count)
typedef void(*exec_func)(void);
inline void exec_bump(exec_func f){
f();
++count;
}
int main(void)
{
int count=0;
while(count++<10){
EXEC_BUMP(g);
//exec_bump(g);
}
return 0;
}
案例之间的差异是否定义局部变量,并使用内联函数与宏。 为什么上面的代码给出不同的输出? 此外,是否有人可以让我知道为什么使用内联函数比宏更有效。
以下输出:
Case 1:
Called g, count=1.
Called g, count=3.
Called g, count=5.
Called g, count=7.
Called g, count=9.
Case 2:
Called g, count=1.
Called g, count=3.
Called g, count=5.
Called g, count=7.
Called g, count=9.
Case 3:
Called g, count=0.
Called g, count=1.
Called g, count=2.
Called g, count=3.
Called g, count=4.
Called g, count=5.
Called g, count=6.
Called g, count=7.
Called g, count=8.
Called g, count=9.
Case 4:
Called g, count=0.
Called g, count=0.
Called g, count=0.
Called g, count=0.
Called g, count=0.
答案 0 :(得分:3)
我认为你的测试有点比较苹果和橘子,尤其是案例3和4.你的宏正在递增本地count
变量,你的内联函数正在递增全局count
变量。 / p>
您将它们命名为count
,但宏会增加本地范围内的宏。这是使用宏时必须注意的事项,因为它们没有范围概念。
我建议将全局变量命名为与本地计数器不同,以避免混淆。
使用宏,它们有点像蛮力'复制和粘贴'代码生成机制,带有一些文本替换。所以当你定义一个像:
的宏#define FOO (++count)
...并调用它,就像将++count
字面写入您调用它的函数中一样。宏扩展总是强有力地在这个意义上内联代码,并且它在编译器和链接器甚至到达它之前就这样做了。预处理器在构建过程中是一个完全独立的阶段,因此宏不遵循内联函数的作用域规则。由于这个原因,我们也倾向于对它们更加小心,因为遇到类似测试的情况可能会让调试变得非常混乱。
另一方面,函数内联实际上是编译时(有时甚至是链接时)优化。生成的目标代码甚至最终二进制文件都没有正常的函数调用开销,将事物推送到堆栈,可能必须通过精确的寄存器传递特定的东西(取决于调用约定)等等。所以你可以得到一个类似的作为宏扩展的一种性能优势,但内联函数尊重语言的范围规则。
值得注意的是,inline
更像是一个暗示,而一些编译器只是直接忽略它并仅将其视为内部链接的说明符。如果您或优化器选择 not 来内联某些东西,实际上可以在现实世界的场景中获得更快的东西,因为它可能有助于减少指令缓存未命中,或者帮助优化器分配寄存器以获得更多常见的案例执行分支(有时程序间优化实际上会干扰您将代码缩减到平坦的竞争环境,当您可能希望优化更偏向于代码的常见情况分支时,过度内联实际上似乎是干扰这一点,并给出更糟糕的结果)。
宏并没有为编译器或链接器选择性地内联提供这样的奢侈,但它们是一种非常不同的代码生成工具。宏可以用于生成新函数,例如,内联函数不能。
答案 1 :(得分:2)
当您想要考虑内联函数时,一个良好的开端可能是令人惊讶的忽略内联。
函数的语义(含义)在内联声明时不会改变一位。它只是编译器优化实现细节的一个提示,并且编译器不会被迫遵守它。另一方面,编译器可以自由地内联未声明为内联的函数,并且大多数现代编译器在使用优化选项执行时都会执行此操作。
另一方面,预处理器宏的含义很简单而且很愚蠢。它是纯文本替换,在翻译阶段之前发生。生成的C程序文本中出现的所有标识符表示它们在代码中该位置的含义。