V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
nobodybutme
V2EX  ›  问与答

i=3 printf("%d %d %d %d\n", i++, ++i, i++, ++i); 求结果解释

  •  
  •   nobodybutme · 2015-07-12 11:37:03 +08:00 · 8145 次点击
    这是一个创建于 3421 天前的主题,其中的信息可能已经有所发展或是发生改变。
    int i=3, j = 3, z = 3;
    printf("%d %d %d %d\n", i++, ++i, i++, ++i);
    printf("%d %d %d %d\n", j++, ++j, ++j, ++j);
    printf("%d %d %d\n", ++z, ++z, ++z);

    结果为:
    6 7 4 7
    6 7 7 7
    6 6 6

    printf 参数从右往左压栈, 我一直以为z的输出应该是6 5 4,有人帮忙解释下么?
    第 1 条附言  ·  2015-07-12 16:08:35 +08:00
    实际中肯定不会写出这种代码,只是偶然看到类似题目就自己试了一下,结果一直搞不明白。

    谢谢大家的解答!
    21 条回复    2015-07-12 17:02:51 +08:00
    zhjits
        1
    zhjits  
       2015-07-12 11:39:08 +08:00
    undefined behavior
    FrankFang128
        2
    FrankFang128  
       2015-07-12 11:40:02 +08:00 via Android   ❤️ 3
    结果就是写这行代码的程序员被开除。
    然后把这行重写
    choury
        3
    choury  
       2015-07-12 11:42:23 +08:00   ❤️ 1
    你学的是谭浩强的C语言吗,要是我们组有人敢写这样的代码,我非得喷死他
    nobodybutme
        4
    nobodybutme  
    OP
       2015-07-12 11:43:20 +08:00
    @zhjits 我win下codeblocks和linux下gcc跑的都是这个结果。 不同编译器怎么实现的? 比如i的那个,6 7 4 7 怎么得出来的?
    onlyice
        5
    onlyice  
       2015-07-12 11:51:16 +08:00
    @nobodybutme 看生成的汇编代码,就知道怎样实现了
    说实话知道了也没什么用
    chaucerling
        6
    chaucerling  
       2015-07-12 11:53:25 +08:00
    ++i的优先级
    lingo233
        7
    lingo233  
       2015-07-12 11:55:30 +08:00
    这一定是谭浩强C
    zhjits
        8
    zhjits  
       2015-07-12 11:58:04 +08:00
    @nobodybutme Windows 下面的 codeblocks 自带一个 gcc。

    Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) 运行结果:
    3 5 5 7
    3 5 6 7
    4 5 6
    zhjits
        9
    zhjits  
       2015-07-12 11:58:41 +08:00   ❤️ 1
    @nobodybutme 至于具体编译器怎么实现的可以 RTFM 或者看生成的汇编啊
    johnsmith123
        10
    johnsmith123  
       2015-07-12 12:11:38 +08:00
    SB
    loveuqian
        11
    loveuqian  
       2015-07-12 12:19:34 +08:00 via iPhone
    了解这段代码的含义对实际开发帮助不大
    nobodybutme
        12
    nobodybutme  
    OP
       2015-07-12 12:23:49 +08:00
    @zhjits Thank you! ^_^
    101
        13
    101  
       2015-07-12 12:27:23 +08:00
    我记得不同的编译器实现是不一样的,类似事例似乎在 TCPL 出现过?
    dndx
        14
    dndx  
       2015-07-12 12:36:55 +08:00
    有时间干啥不好非研究这种蛋疼且毫无意义的玩意。
    18000rpm
        15
    18000rpm  
       2015-07-12 12:41:00 +08:00   ❤️ 1
    你们喷完还是帮人家解决一下问题嘛
    LZ 可以参考一下这个 http://docs.linuxtone.org/ebooks/C&CPP/c/ch16s03.html
    yksoft1
        16
    yksoft1  
       2015-07-12 13:08:56 +08:00
    不同编译器,不同系统,不同CRT对这个实现都可能不同,因此不要在实际开发中这么写
    XiXiLocked
        17
    XiXiLocked  
       2015-07-12 13:10:55 +08:00   ❤️ 1
    这和压栈顺序在概念上是无关的(实现上相关那是另一回事
    有关的是参数的计算顺序,
    比如printf("%d %d %d\n", ++z, ++z, ++z); 补上计算过程中的临时变量,那就相当于7条无序语句
    z+=1;
    int temp1 = z;
    z+=1;
    int temp2 = z;
    z+=1;
    int temp3 = z;
    printf("%d %d %d\n", temp1, temp2, temp3);
    除了print必须最后执行,初始化temp必须在z+=1之后,并没有其他约束。所以temp1,2,3的顺序可以换,temp的初始化的时机也可以后延。要出现666只要把3条temp尽量往后挪就行。

    再说这样写并不好,虽然我觉得这不是undefined behavior,而是implementation specific behavior,因为我记得语言规范上故意不限定求值顺序是为了方便编译器优化,但不管是哪种,代码已经不受自己控制了。
    en3073
        18
    en3073  
       2015-07-12 15:42:45 +08:00
    xcode的答案
    3 5 5 7
    3 5 6 7
    4 5 6
    你怎么看?
    wy315700
        19
    wy315700  
       2015-07-12 15:47:30 +08:00
    函数参数是从右往左压栈,但是没有定义是哪个参数先行计算
    Tink
        20
    Tink  
       2015-07-12 16:31:14 +08:00 via iPhone
    自己算的 3 5 5 7

    3 5 6 7

    4 5 6
    adadada
        21
    adadada  
       2015-07-12 17:02:51 +08:00   ❤️ 1
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2739 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 14:33 · PVG 22:33 · LAX 06:33 · JFK 09:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.