宏生成错误的数字

时间:2015-11-11 17:09:08

标签: c macros

我无法理解为什么以下代码打印2而不是1 ...

#include <stdio.h>
#define ABS(x) ((x) < 0) ? -(x) : (x)
int main()
{
    printf("%d", ABS(ABS(-2)-(ABS(-3))));
    return 0;
}

这个问题在我们的考试中,我回答输出是1但是在编译之后我得到2 ...有人请说明实际表达的内容......提前致谢。

6 个答案:

答案 0 :(得分:3)

你忘记了外括号,试试这个:

#define ABS(x) (((x) < 0) ? -(x) : (x))

答案 1 :(得分:2)

括号有问题。如果展开宏,您将获得复杂的嵌套三元运算,其值为2(请参阅更新中的扩展)。为了得到一个理想的结果用括号围绕宏。

更新:手动扩展:

ABS(ABS(-2)-(ABS(-3)))

扩展为:

((ABS(-2)-(ABS(-3))) < 0) ? -(ABS(-2)-(ABS(-3))) : (ABS(-2)-(ABS(-3)))

ABS(-3)在任何地方都被括号括起来,因此可以安全地评估3,因此无需展开它。所以我们最终:

(( ((-2) < 0) ? -(-2) : (-2) - 3) < 0) ? -(ABS(-2)-3) : (ABS(-2)-3)

(ABS(-2)-3)将扩展为

((-2) < 0) ? -(-2) : (-2) - 3 = 2

评估整体: (( true ? 2 : -5 < 0) ? -2 : 2

(2 < 0) ? -2 : 2 = 2 这是观察到的结果,希望它是可以跟随的。

这是eno

答案 2 :(得分:1)

#include <stdio.h>
#define ABS(x) ((x) < 0) ? -(x) : (x))
int main()
{
    printf( "%d", ABS( ABS(-2) - ABS(-3) ) );
    return 0;
}

您忘记了)中的右括号#define

此外,return必须为小写

我放置了空格,因此您可以更清楚地看到分组。

答案 3 :(得分:1)

带有编译选项-E

http://coliru.stacked-crooked.com/a/59700f453a1dcaf9中的

gcc预处理器解决了这个问题:

printf("%d\n", ABS(ABS(-2)-(ABS(-3))));

到此:

printf("%d\n", ((((-2) < 0) ? -(-2) : (-2)-(((-3) < 0) ? -(-3) : (-3))) < 0) ? -(((-2) < 0) ? -(-2) : (-2)-(((-3) < 0) ? -(-3) : (-3))) : (((-2) < 0) ? -(-2) : (-2)-(((-3) < 0) ? -(-3) : (-3))));

检查你的自己

答案 4 :(得分:1)

您需要围绕ABS定义的表达式使用括​​号。而不是

#define ABS(x) ((x) < 0) ? -(x) : (x)

你需要:

#define ABS(x) (((x) < 0) ? -(x) : (x))
               ^----------------------^

如果不这样,表达式ABS(ABS(-2)-(ABS(-3)))将扩展为:

((((-2) < 0) ? -(-2) : (-2)-(((-3) < 0) ? -(-3) : (-3))) < 0) ?  -(((-2) < 0) ? -(-2) : (-2)-(((-3) < 0) ? -(-3) : (-3))) : (((-2) < 0) ? -(-2) : (-2)-(((-3) < 0) ? -(-3) : (-3)))

分析这将是一个很难理解出错的地方。但是,如果您查看表达式的开头,您将看到第一个术语将进入第二个术语。

((-2) < 0) ? -(-2) : (-2)-(((-3) < 0) ...
                         ^^ (-2) Runs into the next term

表达式的价值难以预测。如果在宏定义的表达式周围添加括号,您将看到:

( (((-2) < 0) ? -(-2) : (-2)) - ( (((-3) < 0) ...
  ^ ------ one term ------- ^ There is no running in to the next term.

答案 5 :(得分:1)

让我们手动扩展这个宏:

ABS(-3) == ((-3) < 0) ? -(-3) : (-3)
ABS(-2) == ((-2) < 0) ? -(-2) : (-2)

ABS(-2) - ABS(-3) ==
  ((-2) < 0) ? -(-2) : (-2) - ((-3) < 0) ? -(-3) : (-3)

现在我们遇到了一个问题:二进制-的优先级高于?:,因此上面的解析为:

((-2) < 0) ? -(-2) : 
  ((-2) - ((-3) < 0) ? -(-3) : (-3))

由于(-2) < 0为真,我们会评估-(-2)。然后:

ABS( ABS(-2) - ABS(-3) ) ==
  ((((-2) < 0) ? -(-2) : (-2) - ((-3) < 0) ? -(-3) : (-3)) < 0 ?
    -(((-2) < 0) ? -(-2) : (-2) - ((-3) < 0) ? -(-3) : (-3)) :
    (((-2) < 0) ? -(-2) : (-2) - ((-3) < 0) ? -(-3) : (-3))

我们已经建立了

((-2) < 0) ? -(-2) : (-2) - ((-3) < 0) ? -(-3) : (-3)

评估为2,因此表达式为

(((-2) < 0) ? -(-2) : (-2) - ((-3) < 0) ? -(-3) : (-3))

得到评估,猜猜是什么?它评估为2

您需要做的是更改您的宏,如下所示:

ABS(x) ( (x) < 0 ? -(x) : (x) )

然后一切都扩展为

ABS(-3) == ((-3) < 0 ? -(-3) : (-3))
ABS(-2) == ((-2) < 0 ? -(-2) : (-2))

ABS(-2) - ABS(-3) ==
  ((-2) < 0 ? -(-2) : (-2)) - ((-3) < 0 ? -(-3) : (-3))

ABS(ABS(-2) - ABS(-3)) ==
  (((-2) < 0 ? -(-2) : (-2)) - ((-3) < 0 ? -(-3) : (-3)) < 0 ?
    -(((-2) < 0 ? -(-2) : (-2)) - ((-3) < 0 ? -(-3) : (-3))) :
     ((-2) < 0 ? -(-2) : (-2)) - ((-3) < 0 ? -(-3) : (-3))

这次,

(((-2) < 0 ? -(-2) : (-2)) - ((-3) < 0 ? -(-3) : (-3))

评估为-1

其余部分应该从这里清楚。

出于这个原因,您应该总是将表达式宏体包装在外部括号中。