|
宏与 inline 函数之间有一些共同之处。 但存在两个重要的差异。 请考虑以下示例:
C++
复制
#include <iostream>
#define mult1(a, b) a * b
#define mult2(a, b) (a) * (b)
#define mult3(a, b) ((a) * (b))
inline int multiply(int a, int b)
{
return a * b;
}
int main()
{
std::cout << (48 / mult1(2 + 2, 3 + 3)) << std::endl; // outputs 33
std::cout << (48 / mult2(2 + 2, 3 + 3)) << std::endl; // outputs 72
std::cout << (48 / mult3(2 + 2, 3 + 3)) << std::endl; // outputs 2
std::cout << (48 / multiply(2 + 2, 3 + 3)) << std::endl; // outputs 2
std::cout << mult3(2, 2.2) << std::endl; // no warning
std::cout << multiply(2, 2.2); // Warning C4244 'argument': conversion from 'double' to 'int', possible loss of data
}
Output
复制
33
72
2
2
4.4
4
下面是宏与内联函数之间的一些差异:
宏始终是内联扩展的。 但内联函数仅当编译器确定内联函数是最佳操作时才会内联。
宏可能会导致意外行为,从而导致微小的 bug。 例如,表达式 mult1(2 + 2, 3 + 3) 展开为 2 + 2 * 3 + 3,其计算结果为 11,但预期结果为 24。 一种看似有效的修复是在函数宏的两个参数周围添加括号,得到 #define mult2(a, b) (a) * (b),这将解决当前的问题,但在处理较大表达式的一部分时仍然可能导致意外的行为。 这种情况已在前面的示例中进行了演示,可以通过将宏定义为 #define mult3(a, b) ((a) * (b)) 来解决该问题。
内联函数受编译器的语义处理约束,而预处理器会扩展宏,但没有任何好处。 宏不是类型安全的,而函数是。
计算一次作为内联函数的参数传递的表达式。 在某些情况下,作为宏的自变量传递的表达式可计算多次。 例如,请考虑如下事项:
C++
复制
#include <iostream>
#define sqr(a) ((a) * (a))
int increment(int& number)
{
return number++;
}
inline int square(int a)
{
return a * a;
}
int main()
{
int c = 5;
std::cout << sqr(increment(c)) << std::endl; // outputs 30
std::cout << c << std::endl; // outputs 7
c = 5;
std::cout << square(increment(c)) << std::endl; // outputs 25
std::cout << c; // outputs 6
}
Output
复制
30
7
25
6
在此示例中,在表达式 sqr(increment(c)) 展开为 ((increment(c)) * (increment(c))) 时调用两次函数 increment。 这导致第二次调用 increment 时返回 6,因此表达式的计算结果为 30。 任何包含副作用的表达式在宏中使用时都可能会影响结果,请检查完全展开的宏以检查该行为是否符合预期。 而当使用内联函数 square 时,将只调用一次 increment 函数,并得到正确结果 25。
|
|