0

我有以下简单的 C 代码

#define Sqrt(A) A * A


int main(void) {

    int A = 10;

    int x = Sqrt(A+1);

    return 0;

}

出于某种原因,当我这样使用它时,使用 A+1,我得到 x 为 21,这可能是 10+11。我的问题是,乘法是如何被忽略的?如果我用宏文本切换宏,我会得到正确的结果,即 121。

谢谢。

4

8 回答 8

5

首先,你Sqrt的名字错了,应该是Square(不是平方根

然后,生成预处理的表单(即使用gcc -C -E)并查看其中的内容。

 #define Sqr(A) A * A

 int a = 10;

 int x = Sqr(a+1);

最后一行扩展为

 int x = a+1 * a+1;

被解析为

 int x = a+(1*a)+1;

故事的寓意,总是在宏定义中使用额外的括号,即

 #define Sqr(A) ((A)*(A))

即使有这样的定义,Sqr(a++)也可能是未定义的行为,至少是顽皮的。

所以你想避免使用宏,实际上,学习使用内联函数,比如

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

static inline顺便说一句,您不仅要使它inline(并将其放在头文件中)

于 2013-06-09T06:34:05.893 回答
3

'cos

#define Sqrt(A) A * A

使

Sqrt(A+1);

翻译成

A + 1 * A + 1

A是10

所以你得到

10 + 1 * 10 + 1

现在做数学!

顺便说一句 sqrt 似乎说平方根不是平方的!

于 2013-06-09T06:33:56.687 回答
3

您将宏定义为A * A. 因此,Sqrt(A + 1)扩展为A + 1 * A + 1,也就是说,由于运算符优先级,等于2 * A + 1- 你有2 * 10 + 1 = 21.

这就是为什么你应该总是给你的宏和它们的参数加上括号:

#define Sqrt(A) ((A) * (A))

顺便说一句,为什么是宏?如果有一天你写作Sqrt(A++)呢?那么你可以期待鼻恶魔。写一个内联函数会更安全(可怕的 dictu,一个正确命名的内联函数):

static inline double square(double x)
{
    return x * x;
}
于 2013-06-09T06:34:30.053 回答
2

在宏内部,A替换为传递给宏调用的任何内容。在这种情况下,即A+1。这意味着宏被扩展为:

A+1 * A+1

由于运算符优先级,这被解释为A + 1*A + 1, 或10 + 10 + 1 = 21

于 2013-06-09T06:35:00.893 回答
1

您应该将宏定义为#define Sqrt(A) ((A) * (A))

于 2013-06-09T06:33:56.600 回答
0

BODMAS 规则哥们!!正如前面的答案所暗示的那样。乘法发生在你的加法之前。您的操作 Sqrt(A+1) 其中 A = 10 将计算为 10+1*10+1 10+10+1 21!!

于 2013-06-09T06:51:56.267 回答
0
when you call x = MACRO_NAME(A+1); this statement is replace as x = A + 1 * A + 1
in c priority of multiplication is more than addition so it will be 1st executed 1*A which give as A, then A+A+1 will give you result as 21`enter code here`
i.e  A+1*A+1 
  =  A+A+1 
  =  21
for proper answer you need to write Macro as #define MACRO_NAME(A) (A) * (A) which give you result as 
121
于 2013-06-09T07:16:13.593 回答
0

宏被逐字替换,然后被评估。

由于乘法比加法具有更高的优先级,因此当您赋予A+1宏时,它变为10 + 1 * 10 + 1=> 10 + 10 + 1=>21

同样,如果你给A+2..... 10 + 2 * 10 + 2=> 10 + 20 + 2=> 32

于 2013-06-09T06:40:30.430 回答