文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

在C90,C99或者C11这些不同的C语言标准版本中,有一些细微的差别可能会导致相同的源代码编译出的程序行为各异。类似的,C++是C的超集,但是也有一些情况会导致C和C++的不同结果。

这是Don Yang在(2015年代码混乱大赛)[http://ioccc.org/]的(作品)[http://ioccc.org/2015/yang/hint.html].这段代码用C89, C99,C11,C++11编译运行会打印出不同的结果。对于C90,它打印出的是下面图中的星星。

*********************************************              ***               **
***********************     *****************             ******             **
*********************        ****************           **********           **
********************         ****************         **************         **
******        ******         *****************     ****************************
******           **          **************************************************
******                      *************************(O************************
*******                     *     *********************************************
*********                              ****************************************
***********                             ***************************************
************                            ***************************************
*********                             *****************************************
*******                     ***************************************************
******                       ****************)d));o((d=************************
******           **          **************************************************
******         *****         *********************      ***********************
********************(         O******************        **********************
**********************       *******************          *********************
************************     *******************          **************)p)-p);
o(d-(p=*****************************************          *********************
第 1 段(可获 2 积分)

对于C99这个星星有眼睛,C++11打印圆圈等等。(这个程序还有更多内容。程序从标准输入读取文本,然后用C90方式混乱之后输出那些文本--所有的*号位置都不一样)

下面是这个程序的源代码,有点难读

                              #define r(R) R"()"
                          /*[*/#include  /**/<stdio.h>
                      #include<math.h>/*!![crc=0f527cd2]*/
                   float I,bu,k,i,F,u,U,K,O;char o[5200];int
              #define R(U) (sizeof('U')==1||sizeof(U"1"[0])==1)
            h=0,t=-1,m=80,n=26,d,g,p=0,q=0,v=0,y=112,x=40;  float
           N(float/*x*/_){g=1<<30;d=-~d*1103515245&--g;return  d*_
          /g;}void/**/w(int/**/_){if(t<0){for(g=0;g<5200;o[g++   ]=
          0);for(;g;o[g+79]=10)g-=80;for(t=37;g<62;o[80+g++]=32)   ;
         }if(m&&o[h*80+m-1]==10){for(g=0;g<79;o[t*80+g++]=0){}o[t
         ++*80+g]=10;t%=64;n+=2;I=N(70)+5;if(n>30&&(I-x)*(I-x)+n*
        n>1600&&R()){O=0;F=(x=0x1!=sizeof(' '))?k=1+N(2),i=12-k+N(
        8),N(4):(k=17+N(5),i=0,r()[0]?O=.1:  0);for(u=U=-.05;u<32;
        U=k+i+i*.5*sin((u+=.05)+F))for( K=0   ;K< U;K+=.1)if((bu=K*
       sin(u/5),g=I+cos( u/5) *K)>=0&&g  <     79  )o[g+(int)(t+44+
       bu*(.5-(bu>0?3*O:  O)   ) )%64*  80      ]  =32;x*=02//* */2
      -1;n=O+x?n=I+(x?0   :N     (k)-   k           /2),g=(t+42  )%
      64,m=-~g%64,x?g=m          =-~        m%64:0  ,n>5?o[g*80   +
     n-3]=o[m*80+n-3]=       0:   0              ,n <75?o[g*80+n
     +2]=o[m*80+n+2]=0   :0:0;                      x=I;}h=-~h%64
    ;m=0;}putchar((g=o [h*                          80+m++])?g:_);
   if(g){w(_);}}void W                               (const char*_
  ){for(;*_;w(*_++));}                               int main(int a
  ,char**_){while(a--)d              +=_[a          ]-(char*)0;W( \
 "#include<stdio.h>typed"             "e"         "f\40int\40O;v"
 "oid o(O _){putchar(_);}O"                    "\40main(){O"  ""
"*_[512],**p=_,**d,b,q;for(b=0;b"        "++<512;p=_+q)_[q"    \
"=(p-_+1)*9%512]=(O*)p;") ;      for(;(g= getchar())-EOF;p=
q){q=p;for(v=512;p-q-g&&q-p-              g;  v--)q=-~q*9%512
;W("o(");if(p>q)w(y),w(45);w(                      40);w(y^=20
);w(075);for(a=0;a<v;a++)w(42);                      for(W("(O**"
 );a--;w(42)){}w(41);w(y^024);w(                      41);if(p<=q)w(
   45),w(y^20);W(");");}for(a=7;a-6                      ;W(a<6?"{;}":""
      ))for(a  =0;a  <6 &&   !o[h*80+m                       +a];a++){}W("r"
         "etu"  /*J   */       "rn+0;}\n"                             );return
             /*                      "#*/0                                   ;}

 

第 2 段(可获 2 积分)

但是我能说的是,顺序使用下面这3个小技巧可以检测用的是哪个版本的C或者C++:

  • 看注释 // 引起的注释

C90 不支持 // 方式注释,所以这条语句

int i = 2 //**/2
    ;

在其他版本的C和C++版本会有不同的表现。在C90,会被编译成(译注:不支持//, 所以/**/ 被编译器去掉)

int i = 2 / 2
    ;

但是在C++和更新的C版本会被编译成(译注://**/2 都被编译器去掉了)

int i = 2
    ;
  • 字符常量的的类型

比如'a', 在C里面会被认为是int类型,但是在C++是char类型。这意味着sizeof('a')在C和C++被计算成不同的值。

  • 宽字符串

C11和C++11支持宽字符串字面值,例如U"hello!” 是字符类型为char32_t的字符串。定义宏

#define  R(U) sizeof(U"a"[0])

对于R(""), 在C11和C++11展开成(译注:认为U"a"是一个token,所以忽略宏参数)

sizeof(U"a"[0])

这会被计算成4.但是在更老的版本里,编译器认为U和“a"是两个符号,这个宏就被展开成(译注:认为U是宏参数,被替换)

sizeof("""a"[0])

也就计算成了1

第 3 段(可获 2 积分)

文章评论