具有运算符优先级的宏功能是否显示异常结果?

时间:2018-08-01 12:03:25

标签: c bitwise-operators

#define SQUARE(x,y) (x<y?x:y)
   int a = 5, b = 6, c = 3;
    int var = SQUARE(a & c,b);

我已经搜索并得知,“ <”在“&”之前。按照规则,它应该为“ 5”。但是它给出的输出为“ 1”。但是在某些情况下,它会给出正确的输出。您能解释一下这方面的宏观规则吗?我在这里想念什么。

3 个答案:

答案 0 :(得分:5)

宏仅被预处理器替换,因此不会评估参数,然后像在函数中那样传递参数。

在您的示例中,表达式SQUARE(a & c, b);将变为(a & c < b ? a & c : b);

对于a=5, b=6, c=3,其计算结果为:

(5 & 3<6 ? 5&3 : 6) //'<' precede '&' as you correctly mentioned
(5&1 ? 5&3 : 6) // '3 < 6' is a boolean expression which evaluates to 1. '&' is bitwise AND.
(1 ? 1 : 6)
(1)

所以1是正确的输出。

编辑:

一个好的方法是始终在参数和整个表达式周围使用括号,以消除运算符优先级的问题。

正如其他人所提到的,由于要进行多次评估,使用宏可能会很危险,这不仅会影响性能。

例如:

#define SQUARE(x) ((x)*(x))

似乎只对参数取平方,但是如果您这样称呼它

f = SQUARE(x++);

您将获得不确定的行为。小型函数的一种更好的方法是将其声明为inline

inline int square(int x)
{
    return x*x;
}

@EricPostpischil宏还提到,它不是文本替换,因为预处理器由令牌替换。

例如:

#define a 1
#define b 2

printf("%d\n", ab);

此处ab不会被12取代,就像有人希望纯文本替换一样。

答案 1 :(得分:3)

宏需要括号,因为它们不是功能,只能进行文本替换

#define SQUARE(x,y) (((x)<(y))?(x):(y))

该宏非常容易出现副作用,并且容易发生UB:

示例:SQUATE(x++,y)

每次在宏中使用x时,示例5和3中的

都会被评估。它将比内联函数

无效
inline unsigned SQUARE(unsigned x, unsigned y)
{
  return (x < y) ? x : y;
}

答案 2 :(得分:1)

如@P__J__所述,更详细一点,宏只是预处理器的文本替换,而不是功能。所以这个:

#define SQUARE(x,y) (x<y?x:y)
int a = 5, b = 6, c = 3;
int var = SQUARE(a & c,b);

被翻译为:

int a = 5, b = 6, c = 3;
int var = (a & c<b?a & c:b);

因为每个xa & c替换,每个y被b替换。

如果您还按照@Osiris的答案来应用这些值,则会得到:

int var = (5 & 3 < 6 ? 5 & 3 : 6);

在这一点上,正如您已经说过的那样,<的优先级高于&

<的结果为true或false,表示10,因此3 < 6变为1

&的结果是两个数字之间的按位AND,在这种情况下,它也是1(因为5101和{{ 1}}是3)。

这就是为什么它成为

011

下一个(5 & 1 ? 1 : 6)也将变成5 & 1(由于1AND之间的101),因此您将获得:

001

由于(1 ? 1 : 6)为真,因此您将获得第一个值,它也是一个1

此外,正如已经指出的,在宏中进行评估时要小心。 这些只是数字,您已经看到了一些不太明显的行为,但是如果将一个函数作为参数之一传递,则该函数将运行多次。

例如

1

将被翻译为

#define SQUARE(x,y) (x<y?x:y)
int var = SQUARE(update_counter(a), 1);

因此有可能两次更新假设的计数器。