Most Pointed Reaction
もっとも集中した反応
受賞者:Don Yang
引用元:https://www.ioccc.org/2015/yang/prog.c
審査員・作者による説明:https://www.ioccc.org/2015/yang/hint.html
動作
メッセージを標準入力に与えると、アスキーアートなC言語コードを出力する。
$ gcc -std=c90 -o prog prog.c -lm
$ echo Hello | ./prog
#include<stdio.h>
typedef int O;void o(O _){putchar(_);}O main(){O*_[512],**p=_,**d,b,q;for(b=0;b
++<512;p=_+q)_[q=(p-_+1)*9%512]=(O*)p;o((d=************************************
****************************************************(O*************************
*****************************************************************)p)-p);o((p=**
*******************************************************************************
*******************************************************************************
*******************************************************************************
****************** **********************************************
************** *********************************************
********** *********************************************
****** ************(O*******************************
**** **********************************************
* ***********************************************
***********************************************
*************************************************
* **************************************************
** ****************************************************
**************************************************
********************************************
*************)d)-d);o(p-(d=*************
**************************************
*************************************
*********** *********************
******* *******************
*** ****** *******************
******** ******** *******************
******** ******* *******************
******** **** *******************
******** * ** ********************
******** *** *********************
********* ***** ***********************
********* ******* ************************
********** ********** **************************
************ ****(O**** ************************
********************* ******************
***************** **************
************** ***********
************* **********
************ *********
************ *********
************ *** **** **********
************** ***** ********** **************
********** ***** *******************************
****** ***** *******************************
**** ****** *******************************
** ******* *******************************
******** ********************************
*********) p));o((p=***********************
************ *(O******************************
********)d)-d);o ((d=*******************************
******************************************************
*************************************************
*********************************************
*******************************************
******************************************
**************** *********************
************ ****************(O*
** *** *********** *******************
*** ***** ********** *******************
*** ***** ******* *******************
*** ***** **** *******************
*** ****** ** ********************
*** ******** *********************
**** ********** ***********************
***** ************ ************************
****** *************** **************************
*****)p )-p);o(d-(p=*** ************************
********************* ******************
***************** **************
************** ***********
************* **********
************ *********
************ *********
************ *** **** ****(O****
************** ***** ********** **************
********** ***** *******************************
****** ***** *******************************
**** ****** *******************************
** ******* ***************************)d))
;return+ 0;}
これを保存してコンパイル・実行すると、元のメッセージが出てくる。
$ echo Hello | ./prog > tmp.c
$ gcc -o tmp tmp.c
$ ./tmp
Hello
アスキーアートは、どういうC/C++の仕様としてコンパイルしたかに依存して変わる。
C89/C90としてコンパイルした場合は、上記と同じ、ヒトデの形。
$ gcc -std=c90 -o prog_c90 prog.c -lm
$ echo A | ./prog_c90
#include<stdio.h>
typedef int O;void o(O _){putchar(_);}O main(){O*_[512],**p=_,**d,b,q;for(b=0;b
++<512;p=_+q)_[q=(p-_+1)*9%512]=(O*)p;o((d=************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
******************************************** ************(O*************** ****
***************************************** ******************* *
**************************************** ************** *
**************************************** ********** *
**************************************** ******* *
***************************************** **** *
****************************************** * **
******************************************* ***
******************************************** ****
********************************************* ******
*******************)p)-p);o((p=**************** *******
********************************************* *****
***************************************
***********************************
*********************************
********************************
*******************************
*******************************
************(O**** **** **** ****
************** ******* *********** ***********
********** ************************ *************
****** ************************ *************
**** ************************* *************
** ************************* *************
************************** **************
*****************)d)-d);{;}{; }return+0;}
C99の場合は、ヒトデに目が入る。
$ gcc -std=c99 -o prog_c99 prog.c -lm
$ echo A | ./prog_c99
#include<stdio.h>
typedef int O;void o(O _){putchar(_);}O main(){O*_[512],**p=_,**d,b,q;for(b=0;b
++<512;p=_+q)_[q=(p-_+1)*9%512]=(O*)p;o((d=************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
************************************************* ***************************
*********************************************** ******************
********************************************** **************
*************(O******************************* **********
********************************************** *******
*********************************************** *****
************************************************ **
*************************************************
**************************************************
***************************************************
***************************************************** *
***************************************************
**************************************)p)-p);
o((p=************************************ * *
***************************************
**************************************
*************************************
*************************************
****************** ********** **** ****
************** ************* *********** *******
********** ******(O********************** *******
****** ****************************** *******
**** ******************************* *******
** ******************************* *******
******************************** ********
*********************************** ********
************************************* *********
*****)d)-d);return+0;}
C++98の場合は、団子の形。
$ g++ -O3 -std=c++98 -o prog_cpp98 prog.c -lm
$ echo A | ./prog_cpp98
#include<stdio.h>
typedef int O;void o(O _){putchar(_);}O main(){O*_[512],**p=_,**d,b,q;for(b=0;b
++<512;p=_+q)_[q=(p-_+1)*9%512]=(O*)p;o((d=************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
********************************************************(O*********************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
******************************** *****************************
************)p)-p);o((p=*** *************************
************************ **********************
********************** ********************
********************* ******************
******************** *****************
******************* ****************
******************* * * ****************
****************** * * **(O************
****************** ****************
******************* ****************
********************* ******************
************************* **********************
******************************* *****************************
*************************************************************)d)-d);return+0;}
C++11の場合は、ただの円。
$ g++ -O3 -std=c++11 -o prog_cpp11 prog.c -lm
$ echo A | ./prog_cpp11
#include<stdio.h>
typedef int O;void o(O _){putchar(_);}O main(){O*_[512],**p=_,**d,b,q;for(b=0;b
++<512;p=_+q)_[q=(p-_+1)*9%512]=(O*)p;o((d=************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
********************************************************(O*********************
*******************************************************************************
************ *****************************************************
******** *************************************************
***** **********************************************
*** ********************************************
* ******************************************
*****************************************
****************************************
***************************************
******)p)-p);o((p=*********************
***************************************
**************************************
**************************************
***************************************
***************************************
***************************************
*********************************(O*****
*****************************************
* *****************************
*** ***************************
***** **************************
******** ****************************
************ ******************************
*******************************************************
******************)d)-d);return+0;}
C11の場合は、アスキーアートを消す。
$ gcc -std=c11 -o prog_c11 prog.c -lm
$ echo A | ./prog_c11
#include<stdio.h>
typedef int O;void o(O _){putchar(_);}O main(){O*_[512],**p=_,**d,b,q;for(b=0;b
++<512;p=_+q)_[q=(p-_+1)*9%512]=(O*)p;o((d=************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
********************************************************(O*********************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*************************************************************************)p)-p)
;o((p=*************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************(O**********************
*******************************************************************************
*******************************************************************************
*******************************************************************************
*****************************)d)-d);return+0;}
解説
コード形状はCLANNADの伊吹風子。
ヒトデが好きという設定のため、それに合わせて、ヒトデのアスキーアートが出力される。
また、出力にポインタ参照の*
が多数含まれているのは、sea star(ヒトデ)とC star(ポインタ参照)を掛けた洒落。
C/C++のバージョンを見分けるトリックは次の通り。
- CとC++を見分けるには、
sizeof('U')
の値を調べる。Cでは'U'
はint
型なので、sizeof('U')
は4や8になる。C++では'U'
はchar
型なので、sizeof('U')
は1になる。
- C++98とC++11を見分けるには、
#define r(R) R"()"
というマクロをr()[0]
と呼び出したときの値を調べる。C++98ではマクロの引数が空なのでR
が無視され、"()"
という文字列の先頭の文字(開きカッコ)を取り出す。C++11ではR"()"
がraw文字列リテラルとなり、()
はデリミタとして無視されるので、空の文字列とみなされる。よってr()[0]
はNUL文字の0を取り出す。
- C90/C99とC11を見分けるには、
#define R(U) sizeof(U"1"[0])==1
というマクロをR()
と呼び出したときの値を調べる。C90/C99では引数が空なのでU
は無視され、sizeof("1"[0])==1
となり、これはchar
型のsizeof
なので1。C11ではU"..."が
const char32_t`型の配列になるので、この式の値は4となる。
- C90とC99を見分けるには、一行コメントの対応状況を使う。次の式は、一行コメントのないC90では
2 / 2 - 1
とみなされて0となり、一行コメントのあるC99では2 - 1
なので1と解釈される。
2 //* */2
- 1
見落としがちだが、生成コードも実は結構興味深い。
先頭の2行で、512要素のポインタの配列の中で、ポインタを512回たどると元の位置にもどる輪を作っている。
文字ごとに***...*
でポインタを何度もたどり、配列先頭からの差の整数をASCIIコードとして出力する、というコードになっている。
実行のたびにアスキーアートが変わるのは、time()
をシードとした乱数ではなく、ASLRをシードとして使っているとのこと。
賢い。cygwinではASLRが効かないので、コマンドライン引数でシードを指定することもできる。
同作者の慣習として、コードに自分自身のCRC32が埋め込まれている(3行目)。
また、開発の様子を撮影したと称するspoiler.htmlも添付されている。
賞名は[[2015/endoh1]]と対称的になっている。