【问题标题】:How will this C preprocessor be evaluated ?如何评估这个 C 预处理器?
【发布时间】:2015-08-11 12:03:58
【问题描述】:
#include<stdio.h>
#define SQUARE(x) x*x
int main(){
float s=10,u=30,t=2,a;
a=2*(s-u*t)/SQUARE(t); // How is this evaluated ? 
printf("Result %f\n",a);
return 0;
}

编译器显示的输出是-100.000000。但根据我的说法,它应该是-25.000000。我应该怎么做才能纠正它,我的错误是什么?

【问题讨论】:

  • #define 执行文字字符串替换。所以你会得到a = 2*(s-u*t)/t*t,给定运算符的求值顺序,它将求值为a = (2*(s-u*t)/t)*t。你可能真的想要a = 2*(s-u*t)/(t*t),所以你应该有#define SQUARE(x) ((x)*(x))
  • FWIW,see this.
  • 最好的了解方式:cpp your_file.c
  • @SouravGhosh 我发现复合文字实际上是运算符。呜呜。
  • @SouravGhosh 是有道理的。

标签: c macros c-preprocessor


【解决方案1】:

#define 对您定义的字符串进行文字替换。所以表达式:

 a = 2*(s-u*t)/SQUARE(t*t)

将扩展为:

 a = 2*(s-u*t)/t*t

给定运算符的评估顺序,将评估为:

a = (2*(s-u*t)/t)*t

不是你想要的。你可能真的想要a = 2*(s-u*t)/(t*t),所以你应该有:

#define SQUARE(x) (x*x)

或者更好,正如@Jongware 指出的那样,因为x 本身可能是一个表达式:

#define SQUARE(x) ((x)*(x))

这样,SQUARE(a+b) 这样的表达式将正确评估为 ((a+b)*(a+b)),而不是 (a+b*a+b)

正如 cmets 中所指出的,当你的参数有副作用时,你需要注意宏表达式的结果。比如SQUARE(x++)做了什么,x做完后的值是多少?在这种情况下,它会给出(x++)*(x++)x 的值被后递增两次,结果可能是未定义的行为(在这种情况下取​​决于后递增的顺序)。

【讨论】:

  • 稍微安全一点:#define SQUARE(x) ((x)*(x))。它将(仅)消除另一个可能的陷阱:SQUARE(1+2)
  • 仅供参考(好吧,我想 知道 - 但为了别人的缘故):这 only 删除了 one陷阱。它不能防止公然滥用,例如SQUARE(x++)
  • @lurker 可能会改写“文字字符串替换”以避免与“字符串文字”和字符串化运算符发生词汇冲突。
  • @Quentin 我改写了一点。不完美,但也许更好。很难避免“字符串”这个词,因此可能会造成混淆。预处理器确实执行“文字字符串替换”,如“文字字符串替换”而不是“所谓的字符串文字的替换”
  • SQUARE(x++) 结果是 UB,对吧?两个增量之间没有序列点...
【解决方案2】:

预处理器是文本替换。所以你的表达变成了:

a=2*(s-u*t)/t*t;

*/ 具有相同的优先级,所以 2*(s-u*t) 除以 t 然后乘以 t

【讨论】:

    【解决方案3】:

    说明:

    宏函数SQUARE(x) x*x计算给定数'x'的平方。

    第一步: float s=10, u=30, t=2, a;这里将变量 s,u,t,a 声明为浮点类型,变量 s,u,t 初始化为 10,30,2。

    第二步: a = 2*(s-u*t)/SQUARE(t);变成,

    => a = 2 * (10 - 30 * 2) / t * t;这里 SQUARE(t) 被宏替换为 t*t 。

    => a = 2 * (10 - 30 * 2) / 2 * 2;

    => a = 2 * (10 - 60) / 2 * 2;

    => a = 2 * (-50) / 2 * 2 ;

    => a = 2 * (-25) * 2 ;

    => a = (-50) * 2 ;

    => a = -100;

    第 3 步: printf("Result=%f", a);它打印变量“a”的值。

    因此程序的输出是-100

    【讨论】:

      【解决方案4】:
      #define SQUARE(x) x*x
      int main(){
      float s=10,u=30,t=2,a;
      a=2*(s-u*t)/t*t; // SQUARE(t) is defined as t*t so it is 
                       // what is placed here instead of SQUARE(t)
      

      这可能不是你想要的,因为/t*t==1

      解决方案:

      #include<stdio.h>
      #define SQUARE(x) ((x)*(x))
      

      然后:

      #include<stdio.h>
      #define SQUARE(x) x*x
      int main(){
      float s=10,u=30,t=2,a;
      a=2*(s-u*t)/((t)*(t)); // again, exactly as in #define SQUARE(t)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-08-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-29
        相关资源
        最近更新 更多