宏定义的常见的三种意外

宏拓展后的大小可能超乎你的想象

这一点没想到例子,以后碰到再补充

对参数的捆绑不如函数严实,会导致意料之外的结果

很常见的一个例子:

#include <stdio.h>
#define square(x) x*x

int main(void) {
int x = 4;
int res = square(x+1);
printf("%d\n", res);
}

编写一个宏,计算 x 的平方。

看上去这段代码没有错,我们得到的答案将会是 25。

实际上呢,我们得到的答案是 11。

为什么呢?我们将 square(x+1)展开

int res = x+1*x+1;

为了避免这种问题,我们应当考虑到宏展开后参数的实际形式。

带有副作用的参数,可能执行次数与预期不同,导致意料之外的结果。

考虑这样的一段代码:

#include <stdio.h>
#define MIN(A,B) ((A) < (B) ? (A) : (B))

int main(void) {
    float x;
    scanf("%f", &x);
    float b = MIN(x++, 1.5);
    printf("%f\n", b);
}

看上去 ,这又是一段没有问题的代码,如果我们输入 1,结果应当是 1。

事实上呢?我们会发现返回的结果是 2。

展开一下

float b = ((x++) < (1.5) ? (x++) : (1.5))

x 在这段宏的执行中,值改变了两次。在比较 a++和 1.5 的时候,先取 1 和 1.5 比较,然后 a 自增 1。接下来条件比较得到真以后又触发了一次 a++,此时 a 已经是 2,于是 b 得到 2,最后 a 再次自增后值为 3。

你应当尽量减少在宏中使用带副作用的参数

参考了这个博客:
https://onevcat.com/2014/01/black-magic-in-macro/