2015-07-21 109 views
2
#include <stdio.h> 
#define ABS(a) (a) < 0 ? -(a) : (a) 
int main(void) 
{ 
    printf("%d\n", ABS(-3) + 1); 
    return 0; 
} 

此代码片段来自Herbert Schildt的书,看起来会产生输出4,但它实际上会打印3。为什么?什么是定义这个C宏的正确方法?

我该如何解决?

+2

尝试扩大自己的宏,看看你会得到什么。请记住,宏不是函数。 – godel9

+0

宏定义的一般规则是将整个事物括起来,并在每次使用宏参数时使用parens - 除非有特定的原因(你可以解释)不要。 –

+0

接下来的问题是'abs( - b)'也会给出错误的答案。 – Jasen

回答

3

展开宏:

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

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

printf("%d\n", (-3) < 0 ? -(-3) : (-3) + 1); // you can get this with **gcc -E source.c 

printf("%d\n", (-3) < 0 ? 3 : -2); //read about precedence to understand this step. 

printf("%d\n", 3); 

这是一步为什么要打印3。您需要使用适当的括号修复它。

4

正确的方法是使用inline函数,对于您要支持的每种类型,使用_Generic大小写。否则你评估a两次。

代替你可以通过在宏中加入表达式来修复它。这总是一个好主意,以防止这类问题。

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

问题就来了,因为有关机构X ? Y : Z + 1X ? Y : (Z + 1)

+0

该解决方案有效。你能告诉我为什么它变成了'Z + 1'吗? '+ 1'不是调用ABS()的一部分吧? – rohithpr

+1

@ praroh1这就是问题所在,宏不是函数,也不会被调用,它们会被代入代码中。 printf(“%d \ n”,(-3)<0? - ( - 3):(-3)+ 1);' - 因此,在'printf'调用看起来像这样预处理后: Z + 1'来自。 – jduncanator

+0

@jduncanator - 啊!现在有道理。谢谢。 – rohithpr

0

修复括号 的#define ABS(一)(((一)< 0) - (一):(一))

1

与函数宏不同的是它们遇到的地方被扩展。 因此,在这段代码

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

时,ABS(-3)遇到它展开,即

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

所以expressoin是真实 - ( - 3)评估(你的情况) 。如果表达式被评估为假(假设),那么结果将是(-3)+1,即-2。

为了解决这个问题,而不是

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

#define ABS(a) ((a) < 0 ? -(a) : (a)) 
相关问题