LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 233|回复: 0

内联函数与宏

[复制链接]
发表于 2024-2-1 21:57:11 | 显示全部楼层 |阅读模式
宏与 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。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表