一段鬼畜的代码

一段鬼畜的代码

有个“国际C语言混乱代码大赛”,简称IOCCC,画风简直鬼畜。其中有个获奖代码是这样的:

main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}

这段代码直接复制粘贴编译运行就输出了当前时间!

C语言果然是强大而灵活。QAQ

注意到源码中有 __TIME__ ,这是预处理器定义的特殊宏,它能扩展为一个字符串,内容为预处理器运行的时间,格式为 "HH:MM:SS"

好奇心驱使着我想要一探究竟。


首先,格式化代码并加入头文件及返回值:

#include <stdio.h>

int main(_)
{
    _ ^ 448 && main(-~_);
    putchar(--_ % 64 ? 32 | -~7[__TIME__ - _ / 8 % 8][">'txiZ^(~z?" - 48] >> ";;;====~$::199"[_ * 2 & 8 | _ / 64] / (_ & 2 ? 1 : 8) % 8 & 1 : 10);

    return 0;
}

展开逻辑与的短路特性,引入变量并化简:

#include <stdio.h>

int main(int i)
{
    if (i ^ 448)
        main(-~i);
    if (--i % 64)
    {
        char a = -~7[__TIME__ - i / 8 % 8][">'txiZ^(~z?" - 48];
        char b = ";;;====~$::199"[i * 2 & 8 | i / 64] / (i & 2 ? 1 : 8) % 8;
        char c = a >> b;
        putchar(32 | (c & 1));
    }
    else
        putchar(10);

    return 0;
}

接下来展开各种位运算并用字符 '\n' 代替其ASCII码值 10

  • if (i ^ 448) 等价于 if (i != 448)
  • -~i 等价于 i + 1
#include <stdio.h>

int main(int i)
{
    if (i != 448)
        main(i + 1);
    i--;
    if (i % 64)
    {
        char a = 1 + 7[__TIME__ - i / 8 % 8][">'txiZ^(~z?" - 48];
        char b = ";;;====~$::199"[i * 2 & 8 | i / 64] / (i & 2 ? 1 : 8) % 8;
        char c = a >> b;
        putchar(32 | (c & 1));
    }
    else
        putchar('\n');

    return 0;
}

递归化为循环,这个有点烧脑:

#include <stdio.h>

int main(void)
{
    for (int i = 447; i >= 0; i--)
        if (i % 64)
        {
            char a = 1 + 7[__TIME__ - i / 8 % 8][">'txiZ^(~z?" - 48];
            char b = ";;;====~$::199"[i * 2 & 8 | i / 64] / (i & 2 ? 1 : 8) % 8;
            char c = a >> b;
            putchar(32 | (c & 1));
        }
        else
            putchar('\n');

    return 0;
}

注意到 putchar(32 | (c & 1)) 取决于 c 的奇偶性,32的二进制表示为 ‭0010 0000‬ ,若 c 为奇数则 putchar(33) 否则putchar(32) 。再分别用字符替换其ASCII码值,得到:

#include <stdio.h>

int main(void)
{
    for (int i = 447; i >= 0; i--)
        if (i % 64)
        {
            char a = 1 + 7[__TIME__ - i / 8 % 8][">'txiZ^(~z?" - 48];
            char b = ";;;====~$::199"[i * 2 & 8 | i / 64] / (i & 2 ? 1 : 8) % 8;
            char c = a >> b;
            if (c % 2)
                putchar('!');
            else
                putchar(' ');
        }
        else
            putchar('\n');

    return 0;
}

接下来,开始分析最长的那两行!

C语言中 a[b] 等价于 b[a] ,这是C语言指针的基础知识,于是有:

char a = 1 + (__TIME__ - i / 8 % 8)[7][">'txiZ^(~z?" - 48]; // 第一次嵌套
char a = 1 + (">'txiZ^(~z?" - 48)[(__TIME__ - i / 8 % 8)[7]]; // 第二次嵌套

得到:

#include <stdio.h>

int main(void)
{
    for (int i = 447; i >= 0; i--)
        if (i % 64)
        {
            char a = (">'txiZ^(~z?" - 48)[(__TIME__ - i / 8 % 8)[7]] + 1;
            char b = ";;;====~$::199"[i * 2 & 8 | i / 64] / (i & 2 ? 1 : 8) % 8;
            char c = a >> b;
            if (c % 2)
                putchar('!');
            else
                putchar(' ');
        }
        else
            putchar('\n');

    return 0;
}

注意到 (i & 2 ? 1 : 8) 取决于 i & 2 的值,展开得到:

#include <stdio.h>

int main(void)
{
    for (int i = 447; i >= 0; i--)
        if (i % 64)
        {
            char a = (">'txiZ^(~z?" - 48)[(__TIME__ - i / 8 % 8)[7]] + 1;
            char b = ";;;====~$::199"[i * 2 & 8 | i / 64];
            if ((i & 2) == 0)  //i & 2 一定要加括号
                b /= 8;
            b %= 8;
            char c = a >> b;
            if (c % 2)
                putchar('!');
            else
                putchar(' ');
        }
        else
            putchar('\n');

    return 0;
}

这里 char a 这一行很奇怪,字符串减去一个整数再取下标?!先写两个demo看看是什么情况(当前时间 18:47):

#include <stdio.h>

int main(void)
{
    char a = (__TIME__ - 7)[7];
    printf("%c\n", a);
    return 0;
}

编译通过!运行发现:

__TIME__的第一位字符?

#include <stdio.h>

int main(void)
{
    char a = (__TIME__ - 6)[7];
    printf("%c\n", a);
    return 0;
}

__TIME__的第二位字符?

所以,(__TIME__ - i)[7] 等价于 (__TIME__)[7 - i]

事实上,这里不能把源代码中的字符串看成数组而应该看成指针。

下标操作默认是 a[i] = *(a + i) 实现的,当然也就有 (a + n)[i] 等价于 a[i + n]

至此,程序分析到这一步:

#include <stdio.h>

int main(void)
{
    for (int i = 447; i >= 0; i--) // 一共7行,每行64个字符,一共循环7x64=448次
        if (i % 64) // 每输出64个字符就换行
        {
            char a = ">'txiZ^(~z?"[__TIME__[7 - i / 8 % 8] - 48] + 1;
            char b = ";;;====~$::199"[i * 2 & 8 | i / 64];
            if ((i & 2) == 0)
                b /= 8;
            b %= 8;
            char c = a >> b;
            if (c % 2)
                putchar('!');
            else
                putchar(' ');
        }
        else
            putchar('\n');

    return 0;
}

分析不下去了。


上网找吧,找到了一篇分析得比较好的文章:StackOverflow


编辑于 2019-08-21

文章被以下专栏收录

    C, Python, Java(OOP), Scheme(FP), Linux, Mathematica, MATLAB, Multisim, NetLogo. 【个人博客】https://chen-qingyu.github.io/ 【微信公众号】acodecat