使用函数与宏时,为什么会得到不同的结果?

时间:2013-11-25 00:20:27

标签: c function macros c-preprocessor

我正在使用DevCPP IDE,我发现用c编程时,

返回的值:

float f(float x)
{
      return 1/(1+x*x);
}

和f(x)返回的值,如果它被定义为:

#define f(x) 1/(1+x*x)

是不同的。

为什么我在这些情况下会得到不同的结果?

编辑:

这是我的代码,我得到了异常:

main()    
{
      int i;

      float a=0, b=1, h, n=12, s1, s2=0;

      h=(b-a)/n; //step length

      s1=f(a)+f(b);

      for(i=1;i<=n-1;i++)

      {

        s2+=f(a+(i*h));

      }

      s1=(s1+2*s2)*h/2;

      printf("sum: %f", s1);   

      getch();
}
  

输出1:0.693581(使用MACRO)

     

OUTPUT 2:0.785109(使用功能)

3 个答案:

答案 0 :(得分:3)

这里有许多的可能性。这里有几个。

在函数版本中,参数显式地输入为float。这意味着如果你打电话

f(1);

然后将1转换为float 1.0f作为参数。然后,当计算1 / (1 + x * x)时,它的计算结果为1 / 2.0f,它出现在0.5f。但是,在宏版本中,f(1)将使用整数除法计算为1 / 2,从而产生值0.

其次,在函数版本中,参数仅计算一次。这意味着

int x = 0;
f(x++);

会将x增加到1,然后传入值0。结果将是1.0f。但是,在宏版本中,代码会扩展为

1 / (1 + x++ * x++)

这会导致未定义的行为,因为x++的评估之间没有序列点。该表达式可以评估为任何,或者它可能会直接使程序崩溃。

最后,函数版本遵循运算符优先级,而宏则不支持。例如,在函数版本中,调用

f(1 - 1)

将致电f(0),评估为1.0f。在宏版本中,这将扩展为

  1 / (1 + 1 - 1 * 1 - 1)
= 1 / (1 + 1 - 1 - 1)
= 1 / 0

由于零除错误,这会导致未定义的行为。

避免这种情况的简单方法是不使用宏来定义函数。回到Bad Old Days这是一个标准的做法,但是现在C有inline函数和编译器更聪明,你应该更喜欢函数到宏。它们更安全,更易于使用,更难搞乱。它们也是类型识别的,不会多次评估参数。

希望这有帮助!

答案 1 :(得分:1)

#define f(x) 1/(1+x*x)

应定义为

#define f(x) 1/(1+(x)*(x))

答案 2 :(得分:0)

试试这个:

#define f(x) (1/(1+x*x))

#define基本上将代码粘贴到#define'名称所在的位置,因此操作和优先顺序将适用。