我是C的新手并试图理解C中的MACRO扩展逻辑。 我想知道为什么第一种方法不起作用,但第二种方法按预期工作。
第一种方法
#include <stdio.h>
#define square(x) x*x
int main()
{
int x = 36/square(6); // Expended as 36/6*6
printf("%d", x);
return 0;
}
// Output: 36
第二种方法
#include <stdio.h>
#define square(x) x*x
int main()
{
int x = square(6)/36; // Expended as 6*6/36
printf("%d", x);
return 0;
}
// Output: 1
有人可以解释我的区别吗?
答案 0 :(得分:2)
6*6/36
扩展为
(6*6)/36
相当于
1
显然等于{{1}}。
尽管这显然是为了理解宏而你可能已经意识到这一点,但有一个建议: 涉及操作符的宏应该被parantheses包围!
答案 1 :(得分:0)
首次扩展
36/6*6
使用优先权规则并从左到右http://en.cppreference.com/w/c/language/operator_precedence将其作为
36/6 * 6 -> (36 / 6) * 6 -> 6 * 6 -> 36
第二次扩张
6*6/36 -> (6 * 6)/36 -> 36 / 36 -> 1
使用上面的优先顺序/从左到右的规则。
对不起,链接 - 不想要刀具。乘法的优先级高于除法
答案 2 :(得分:0)
您的宏应定义为
#define square(x) ((x)*(x))
必须将x括在括号中,以防止出现有关运算符优先级的任何意外。外括号也是出于同样的原因。
请注意,如果参数是自修改表达式,即使上面更正的宏也不起作用。因此,您可能需要考虑将其置于全大写或其他内容,以警告宏的用户它将不会与函数调用等效。
你扩展36 /平方(6)的原因并不像你期望的那样是因为它的扩张。
36/square(6)
36/6*6
6*6 <-- 36/6 evaluated
36 <-- 6*6 evaluated
校正后的宏将会扩展
36/((6)*(6))
36/(36)
1
您期望的答案是什么。另请注意,由于内括号,5 + 1也可以作为参数起作用,但是如果将宏作为函数读取,y ++将不会像您期望的那样运行,因此我建议将其命名为SQUARE以提醒用户这是一个宏不是一个功能。
如果宏的每个参数只出现一次,并且语法就像表达式(即没有{}'),则宏只表现为函数。此外,用户无法将指针传递给宏,因为它们可以传递给函数。
答案 3 :(得分:0)
您的问题很好地说明了宏出现的问题:
36/square(6)
扩展为36/6*6
,根据C语法解析为
(36 / 6) * 6
评估为36
。
如果您已将宏定义为
#define square(x) ((x)*(x))
这两个表达式都是等效的,并且评估为1
。
然而这个宏仍然存在问题:
square(i++)
展开为((i++) * (i++))
。
在同一表达式中两次评估i++
是未定义的行为。