以下程序在C89模式下编译输出"C89",在C99模式下编译输出"C99",原因是什么?

131

我在网上找到了这个C程序:

#include <stdio.h>

int main(){

    printf("C%d\n",(int)(90-(-4.5//**/
    -4.5)));

    return 0;
}

这个程序有趣的地方在于,当以C89模式编译和运行时,它会打印C89,而当以C99模式编译和运行时,则会打印C99。但我无法弄清楚这个程序是如何工作的。

你能解释一下上述程序中 printf 的第二个参数是如何工作的吗?


48
提示:C99引入了C++风格的//注释。 - Paul R
4
好的技巧,但在gcc中会失败。如果没有使用std=c99选项,你将会收到一个警告,即使你忽略了它,gcc仍然会将//解释为注释的开头(啊 - 你还需要使用-pedantic选项。我默认已经开启了它)。 - Jongware
3
嗨,@Jongware。我在gcc 4.9.2中使用显式的std=c89选项得到了符合C89标准的编译结果。 - ikh
63
如果有人正在寻找测试C99支持的方法,请使用类似于 #if __STDC_VERSION__ >= 199901L 的方式,而不是使用 // 注释技巧。 =) - Arkku
10
它在 C11 中也会输出 "C99"。 - Lundin
显示剩余6条评论
3个回答

135

C99允许//风格的注释,C89则不行。因此,要进行翻译:

C99:

 printf("C%d\n",(int)(90-(-4.5     /*Some  comment stuff*/
                         -4.5)));
// Outputs: 99

C89:

printf("C%d\n",(int)(90-(-4.5/      
                         -4.5)));
/* so  we get 90-1 or 89 */

25

自C99起,引入了行注释//。因此,你的代码相当于在C89中:

#include <stdio.h>

int main(){

    printf("C%d\n",(int)(90-(-4.5/
-4.5)));

    return 0;
}
/* 90 - (-4.5 / -4.5) = 89 */

在C99中也等同于此

#include <stdio.h>

int main(){

    printf("C%d\n",(int)(90-(-4.5
-4.5)));

    return 0;
}
/* 90 - (-4.5 - 4.5) = 99*/

9

由于//注释仅存在于C99及更高版本的标准中,因此该代码等效于以下内容:

#include <stdio.h>

int main (void)
{
  int vers;

  #if   __STDC_VERSION__ >= 201112L
    vers = 99; // oops
  #elif __STDC_VERSION__ >= 199901L
    vers = 99;
  #else
    vers = 90;
  #endif

  printf("C%d", vers);

  return 0;
}

正确的代码应该是:

#include <stdio.h>

int main (void)
{
  int vers;

  #if   __STDC_VERSION__ >= 201112L
    vers = 11;
  #elif __STDC_VERSION__ >= 199901L
    vers = 99;
  #else
    vers = 90;
  #endif

  printf("C%d", vers);

  return 0;
}

你的答案中出现了一处“差一”的错误,为什么会输出90而不是89呢? - Pimgd
1
@Pimgd C89和C90是同一件事情。https://dev59.com/N2Qm5IYBdhLWcg3w-S2Y#17209532 - Lundin
3
它们的意思相同,但不是同一个字符串。坚持我的原始问题。 - Pimgd
@Pimgd 上述代码的目的不是为了满足某些人工任务,以在给定格式后打印字符串。目的是演示现实世界应用程序如何打印编译程序所使用的C版本,而不是IOCCC(http://www.ioccc.org/)。 C90比“ C89”或“ ANSI-C”更正确使用。 - Lundin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接