C中的宏用法?

时间:2015-12-12 16:36:02

标签: c macros

我是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

有人可以解释我的区别吗?

4 个答案:

答案 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++是未定义的行为。