• 【C语言】一句printf代码——{ a[0] ? 0[a] }


    这是前段时间做的http://fun.coolshell.cn/中的一道题,很有意思,涉及的其实是C的基础,不过当时第一次看见这行代码确实把我弄懵了:

    printf(&unix["21%six12"], (unix)["have"] + "fun" - 0x60);

     当时在网上一搜,有仁兄给出了全句的解释:http://blog.itpub.net/12443821/viewspace-671745/

    这里呢,我就用我的理解再解释一下,至少更符合我的理解思路~我是第一次见这种写法,C语言前辈们请略过~

    分成下面几个部分来解析这行代码:

    一、21 12 是什么意思

    abc表示是八进制表示的ASCII码,所以21就是17对应的ASCII码(2^8+1=17),12是10,就是0,所以,代码约等于下面的表示,ascii的17表示的字符有点怪,就用@代替:

    printf(&unix["@%six
    "], (unix)["have"] + "fun" - 0x60);

    二、unix是什么

    这个确实不大容易知道,如果在windows上运行这行代码,是要报错的,因为没有定义unix,这是传说中编译器内置的宏,可能是gcc内置的吧,没有查过,反正相当于有:

    #define unix 1

    三、(0[a] == a[0]) ? true : false

    下面就看看(unix)["have"]是什么东西,当时我就是被这个弄懵了,就算知道unix表示1,那么1["have"]是啥啊?

    char *b = "qwe";
    printf("%c", b[1]);

    看看这两行的输出是啥,很明显,输出字符数组b的第二项"w",这个大家都知道,而且大家也都很清楚,这实际上是:

    printf("%c", *(b+1));

    这个原理就很明显了,b[1]等价于*(b+1)等价于*(1+b),而1[b]不就正表示这个地址嘛~

    到了这就一切清晰了,上面的代码就变成了:

    char * s1 = "have";
    char * s2 = "fun";
    printf(&unix["@%six
    "], s1[1] + s2 - 0x60);

    四、地址运算

    s1[1]+s2-0x60,这个对应前面的%s,是个字符串,很明显,s1[1]是一个char(这里表示字母a),或者是一个数(a的ascii码97,或十六进制表示0x61)。

    s2是"fun"这个字符串的首字符地址,0x60是个数,所以s1[1]-0x60先进行运算,得到1,于是该问题变为:

    char * s2 = "fun";
    printf(&unix["@%six
    "], s2 + 1);

    s2+1就是un了,也就是前面的%s,于是世界一下子清晰了:

    printf(&unix["@unix
    "]);

    五、柳暗花明

    先看unix["@unix "],和前面一样,表示(前面直接删掉并不很合理,用变量s来声明,这个就是自动被添加的了):

    char * s = "@unix
    ";
    printf(&s[1]);

    s[1]表示字母u,&s[1]表示u的地址,就变成了输出"unix "。

    所以最终的结果就是unix。

  • 相关阅读:
    HDU 2896 病毒侵袭 AC自动机
    AC自动机
    BZOJ2337: [HNOI2011]XOR和路径 期望概率dp 高斯
    BZOJ4008. [HNOI2015]亚瑟王 期望概率dp
    BZOJ 2707: [SDOI2012]走迷宫 拓扑+高斯消元+期望概率dp+Tarjan
    CodeForces743E. Vladik and cards 二分+状压dp
    BZOJ 3270 博物馆 && CodeForces 113D. Museum 期望概率dp 高斯消元
    BZOJ1415: [Noi2005]聪聪和可可 最短路 期望概率dp
    CodeForces 167B
    [HEOI2017]分手是祝愿 期望概率dp 差分
  • 原文地址:https://www.cnblogs.com/smarterplanet/p/3959327.html
Copyright © 2020-2023  润新知