面试题答案
一键面试频繁调用场景
- 宏函数:
- 性能影响:在频繁调用时,宏函数由于是代码替换,不会产生函数调用的开销(如保存寄存器、设置栈帧等),所以执行效率相对较高。
- 案例:
#include <stdio.h>
#define MAX(a, b) ((a) > (b)? (a) : (b))
int main() {
int x = 5, y = 10;
int result;
for (int i = 0; i < 1000000; i++) {
result = MAX(x, y);
}
return 0;
}
这里每次调用MAX
宏函数,实际是将宏代码直接展开,无函数调用开销。
- 普通函数:
- 性能影响:频繁调用普通函数会产生函数调用开销,每次调用都要进行压栈、跳转、出栈等操作,在频繁调用场景下,这些开销会显著影响性能。
- 案例:
#include <stdio.h>
int max(int a, int b) {
return (a > b)? a : b;
}
int main() {
int x = 5, y = 10;
int result;
for (int i = 0; i < 1000000; i++) {
result = max(x, y);
}
return 0;
}
这里每次调用max
函数都有函数调用开销,在循环频繁调用时,性能低于宏函数版本。
代码优化场景
- 宏函数:
- 性能影响:宏函数展开后可能导致代码体积增大,如果宏定义比较复杂,可能会使目标代码变得冗长,不利于代码的优化,尤其在空间受限的环境下可能成为问题。另外,宏函数不进行类型检查,可能引入不易察觉的错误。
- 案例:
#define SQUARE(x) ((x) * (x))
int main() {
int a = 5;
int b = SQUARE(a + 1);
// 宏展开为((a + 1) * (a + 1)),如果不小心写为SQUARE a + 1,可能不会报错但结果错误
}
- 普通函数:
- 性能影响:普通函数代码相对简洁,编译器可以对函数进行优化,如内联优化等。现代编译器在优化时可以根据具体情况决定是否将函数内联,避免函数调用开销,同时函数有严格的类型检查,代码更健壮。
- 案例:
int square(int x) {
return x * x;
}
int main() {
int a = 5;
int b = square(a + 1);
// 编译器可以对square函数进行内联等优化,且类型检查严格
}
在优化时,编译器可以针对square
函数进行更有效的优化策略,比如内联函数优化,将函数代码嵌入调用处,避免函数调用开销,同时保证类型安全。