#define SQUARE(x,y) (x<y?x:y)
int a = 5, b = 6, c = 3;
int var = SQUARE(a & c,b);
我已经搜索并得知,“ <”在“&”之前。按照规则,它应该为“ 5”。但是它给出的输出为“ 1”。但是在某些情况下,它会给出正确的输出。您能解释一下这方面的宏观规则吗?我在这里想念什么。
答案 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);
因为每个x
被a & c
替换,每个y被b
替换。
如果您还按照@Osiris的答案来应用这些值,则会得到:
int var = (5 & 3 < 6 ? 5 & 3 : 6);
在这一点上,正如您已经说过的那样,<
的优先级高于&
。
<
的结果为true或false,表示1
或0
,因此3 < 6
变为1
。
&
的结果是两个数字之间的按位AND
,在这种情况下,它也是1
(因为5
是101
和{{ 1}}是3
)。
这就是为什么它成为
011
下一个(5 & 1 ? 1 : 6)
也将变成5 & 1
(由于1
和AND
之间的101
),因此您将获得:
001
由于(1 ? 1 : 6)
为真,因此您将获得第一个值,它也是一个1
。
此外,正如已经指出的,在宏中进行评估时要小心。 这些只是数字,您已经看到了一些不太明显的行为,但是如果将一个函数作为参数之一传递,则该函数将运行多次。
例如
1
将被翻译为
#define SQUARE(x,y) (x<y?x:y)
int var = SQUARE(update_counter(a), 1);
因此有可能两次更新假设的计数器。