宏替换赋值
Macro Substitution assignment
#define MAX(x,y)(x)>(y)?(x):(y)
main()
{
int i=10,j=5,k=0;
k==MAX(i++,++j);
printf("%d %d %d",i,j,k);//11 7 0
}
为什么输出是 11 7 0 而不是 11 6 0?
用实数表达式扩展宏:
k == (i++) > (++j) ? (i++) : (++j);
expr1 ? expr2 : expr3;
这是一个典型的条件表达式。
expr1
是 k == (i++) > (++j)
。这里其实包含了两个逻辑操作。因为 ==
的优先级低于 >
,所以首先评估此逻辑 (i++) > (++j)
,并且 ++j
在第一次逻辑测试之前完成。 j
现在是 6,我们有 10 > 6
是真的 (1
)。现在来看第二个逻辑 k == 1
,它的计算结果为假 (0
)。
- 因为
expr1
是假的,所以 expr3
被评估,即 (++j)
并且 ++ post-fix 意味着 j
在评估之前递增. j
现在变成 7.
预处理器将宏替换为三元运算符:
k == (x) > (y) ? (x) : (y)
比较:(x)>(y)
将首先完成并产生 1,但随后不会评估三元运算符的其余部分,因为运算符 ==
具有优先权。代码相当于:
( k == ( (x) > (y) ) ) ? (x) : (y)
我们必须将该结果(为 1)与 k 进行比较:k==(x)>(y)
,这将产生结果 0。然后将仅评估三元运算符的第三个运算符:(y)
.
总而言之,i
会被评估一次,j
会被评估两次。所以最终结果是 i
为 11,j
为 7。 (变量 k
将保持为 0,因为它从未被赋值。)
语句扩展为
k==(i++)>(++j)?(i++):(++j)
让我们 re-write 添加一些括号来强调在考虑优先规则时如何解析表达式:
( k == ( (i++) > (++j) ) ) ? (i++) : (++j)
请注意 >
的优先级高于 ==
。
现在,首先评估 (i++) > (++j)
,它评估为 1
,并且 i
和 j
都会递增。然后将 k
与 1
进行比较,得出 0
。因此,条件运算符的计算结果为 (++j)
,因此 j
又增加了一次。
总共i
递增一次,j
递增两次,k
没有修改。因此输出如您所描述。
这是使用宏的危险的一个很好的例子。一个函数,正是你所需要的。
其他几点:
- 您的
main
声明不正确。应该是 int main(void)
.
- 如果您在启用警告的情况下进行编译,编译器将标记有问题的行。我的编译器说:
C:\Users\blah\Desktop>gcc main.c -Wall -o main.exe
main.c: In function 'main':
main.c:2:20: warning: suggest parentheses around comparison in operand of '==' [-Wparentheses]
#define MAX(x,y)(x)>(y)?(x):(y)
^
main.c:6:8: note: in expansion of macro 'MAX'
k==MAX(i++,++j);
^
宏是您在定义它们时需要小心的地方,它们不一定会按照您期望的方式扩展。 C 中的宏的一个关键特性是它们逐字逐句地执行替换。
这个概念在K&R的书上都有很好的解释,网上也有很多教程,就google吧。
#define MAX(x,y)(x)>(y)?(x):(y)
main()
{
int i=10,j=5,k=0;
k==MAX(i++,++j);
printf("%d %d %d",i,j,k);//11 7 0
}
为什么输出是 11 7 0 而不是 11 6 0?
用实数表达式扩展宏:
k == (i++) > (++j) ? (i++) : (++j);
expr1 ? expr2 : expr3;
这是一个典型的条件表达式。
expr1
是k == (i++) > (++j)
。这里其实包含了两个逻辑操作。因为==
的优先级低于>
,所以首先评估此逻辑(i++) > (++j)
,并且++j
在第一次逻辑测试之前完成。j
现在是 6,我们有10 > 6
是真的 (1
)。现在来看第二个逻辑k == 1
,它的计算结果为假 (0
)。- 因为
expr1
是假的,所以expr3
被评估,即(++j)
并且 ++ post-fix 意味着j
在评估之前递增.j
现在变成 7.
预处理器将宏替换为三元运算符:
k == (x) > (y) ? (x) : (y)
比较:(x)>(y)
将首先完成并产生 1,但随后不会评估三元运算符的其余部分,因为运算符 ==
具有优先权。代码相当于:
( k == ( (x) > (y) ) ) ? (x) : (y)
我们必须将该结果(为 1)与 k 进行比较:k==(x)>(y)
,这将产生结果 0。然后将仅评估三元运算符的第三个运算符:(y)
.
总而言之,i
会被评估一次,j
会被评估两次。所以最终结果是 i
为 11,j
为 7。 (变量 k
将保持为 0,因为它从未被赋值。)
语句扩展为
k==(i++)>(++j)?(i++):(++j)
让我们 re-write 添加一些括号来强调在考虑优先规则时如何解析表达式:
( k == ( (i++) > (++j) ) ) ? (i++) : (++j)
请注意 >
的优先级高于 ==
。
现在,首先评估 (i++) > (++j)
,它评估为 1
,并且 i
和 j
都会递增。然后将 k
与 1
进行比较,得出 0
。因此,条件运算符的计算结果为 (++j)
,因此 j
又增加了一次。
总共i
递增一次,j
递增两次,k
没有修改。因此输出如您所描述。
这是使用宏的危险的一个很好的例子。一个函数,正是你所需要的。
其他几点:
- 您的
main
声明不正确。应该是int main(void)
. - 如果您在启用警告的情况下进行编译,编译器将标记有问题的行。我的编译器说:
C:\Users\blah\Desktop>gcc main.c -Wall -o main.exe main.c: In function 'main': main.c:2:20: warning: suggest parentheses around comparison in operand of '==' [-Wparentheses] #define MAX(x,y)(x)>(y)?(x):(y) ^ main.c:6:8: note: in expansion of macro 'MAX' k==MAX(i++,++j); ^
宏是您在定义它们时需要小心的地方,它们不一定会按照您期望的方式扩展。 C 中的宏的一个关键特性是它们逐字逐句地执行替换。
这个概念在K&R的书上都有很好的解释,网上也有很多教程,就google吧。