MST

星途 面试题库

面试题:C++宏定义中的副作用与上下文敏感性

考虑如下宏定义`#define INC(x) ++x`。如果在代码中有`int a = 5; int b = INC(a) + INC(a);`,请分析可能出现的问题以及不同编译器下可能的结果。如何修改宏定义以使其行为更可预测?
30.9万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

可能出现的问题及不同编译器结果

  1. 问题:宏INC(x)在表达式INC(a) + INC(a)中会导致未定义行为。因为宏只是简单的文本替换,替换后为int b = ++a + ++a;,在同一表达式中多次对a进行自增操作,且自增操作与取值操作顺序不明确,这属于未定义行为。
  2. 不同编译器结果
    • 某些编译器:可能会按照从左到右的顺序计算,先执行第一个++aa变为6,再执行第二个++aa变为7,最后b = 7 + 7 = 14
    • 另一些编译器:可能会以不同顺序计算,例如先计算第二个++aa变为6,再计算第一个++aa变为7,最后b = 7 + 7 = 14 。但也有可能编译器会进行优化,采用其他计算顺序,得到不同的结果。

修改宏定义使其行为更可预测

  1. 方法一:使用函数替代宏

    int inc(int x) {
        return ++x;
    }
    

    然后在代码中使用int b = inc(a)+inc(a);,这样通过函数调用,每次调用inc函数时,参数求值和函数执行顺序明确,不会出现未定义行为。

  2. 方法二:如果仍然希望使用宏,可以通过引入临时变量来明确计算顺序

    #define INC(x) ({ int temp = x; ++temp; temp; })
    

    这里使用了GCC扩展语法(({...})),先将x的值赋给临时变量temp,对temp自增并返回temp的值。这样在int b = INC(a) + INC(a);中,每个INC(a)都有明确的计算顺序,避免了未定义行为。

    注意,如果不使用GCC扩展语法,也可以通过更为复杂的宏定义来实现类似功能,但这种方法相对简洁。