×

Loading...
Ad by
  • 推荐 OXIO 加拿大高速网络,最低月费仅$40. 使用推荐码 RCR37MB 可获得一个月的免费服务
Ad by
  • 推荐 OXIO 加拿大高速网络,最低月费仅$40. 使用推荐码 RCR37MB 可获得一个月的免费服务

贴这个题时, 就没把他当成coding style issue; 想问的就是编译器的行为; 您的分析,简单化为coding风格不妥,绕开了原来的关键点,所以问题没得到解决;

基于这样的考虑, "94 57"(#5421055),给出了编译器的行为和结果,就可以认为对了,这个上贴错序的小错是一目了然的,大家都明白,不用在这种细枝末节上纠缠了;

volatile x,y放到全局变量处或自动变量在这里对编译器的行为没有影响;这样写的目的是用简单的方法敏化问题;

上面的讨论中很多大侠提到了编译器问题,这是解决问题的关键思路;看看上面的反汇编,应该能得到具体的解释;

另外,绕开了根本问题,指责原问题问得幼稚或错误, 这个解决“问题”的方法我以前用过, 没用; 对解决问题或增加自己的credit都没用; 不管说自己是SMTS,或CTO,全没用;
Report

Replies, comments and Discussions:

  • 工作学习 / 学科技术讨论 / 廉颇老亦, 谁能告诉我结果,并告诉我原因? ( C question)
    main()
    {
    int x=20,y=35;
    x=y++ + x++;
    y= ++y + ++x;
    printf(“%d%d\n”,x,y);

    }


    main()
    {
    volatile int x=20,y=35;
    x=y++ + x++;
    y= ++y + ++x;
    printf(“%d%dn”,x,y);

    }
    • 第一个结果是 94 57?第二个不清楚, 忘了volatile是啥意思了。
      x=y++ + x++ : x=20+35 +1=56, y=36
      y=++y + ++x : y=1+36 + 1+56= 94
      • second thought. 93,56
        x=y++ + x++ : x=20+35 =55, y=35+1=36
        y=++y + ++x : y=1+36 + 1+55= 93, x=55+1=56
        • 2259
          • 看来用CACHE跟不用还是有很大区别的嘛。
            • volitale的作用好象不是禁Cache而是禁Reg吧?
      • 对的; 第二个呢? 牛哥,猫哥,车哥怎么都躲起来了?
        • 牛人们是不需要做这些的,打发手下的实习生和苦力们去干就可以了。:P
          • 是啊,我也觉得我自己不需要做这些,但不做不行啊,你看,关键时候全躲起来了。 :-)
        • 2. Depends on external change (interrupt service or mapped hardware) in embedded system. 1. I had the 2nd thought, which one is correct or depends on compiler?
          • 1) is clear, #5421290@0; but i got confussed with the running result with is 2259, i guess something wrong somewhere;
        • 呵呵,我已经15年没编过代码了,不是干这行的。本科那会儿学的那些基本编程的东西也早忘光了。
          本文发表在 rolia.net 枫下论坛Googled


          [Bug c/17282] x = y++ + x++ operation wrongly implemented on solaris version
          From: "gaurav_har at rediffmail dot com" <gcc-bugzilla at gcc dot gnu dot org>
          To: gcc-bugs at gcc dot gnu dot org
          Date: 3 Sep 2004 05:12:41 -0000
          Subject: [Bug c/17282] x = y++ + x++ operation wrongly implemented on solaris version
          References: <20040902120650.17282.gaurav_har@rediffmail.com>
          Reply-to: gcc-bugzilla at gcc dot gnu dot org

          --------------------------------------------------------------------------------

          ------- Additional Comments From gaurav_har at rediffmail dot com 2004-09-03 05:12 -------
          Hi,

          It seems to me that this problem is different for what defined in other bug.
          Here we are assigning a value after adding and the variable with other
          constant, but instead of adding then incrementing the variable compiler is just
          incrementing the value. Behavior is different in Linux.

          Code is:
          x=20;
          y=35;

          x = y++ + x++;

          For this expression compiler should first add x and y and then increment x.
          This expression should be broken like this.
          x = x + y;
          y++;
          x++;

          but compiler on Solaris is doing something like this:
          temp = x++;
          temp1 = y++;
          x = x + y;
          y = temp1;
          x = temp; /* reassigning the variable with incremented value. This is wrong */

          expected value of x here is 56, but its giving 21.

          Same is working fine with Linux. this problem is there with Solaris and
          compilers cc and g++ also.

          Regards,
          Gaurav


          --
          What |Removed |Added
          ----------------------------------------------------------------------------
          Status|RESOLVED |UNCONFIRMED
          Resolution|DUPLICATE |


          更多精彩文章及讨论,请光临枫下论坛 rolia.net
          • 佩服!站的高度的确不一样!我经常纠缠于具体细节,缺乏outside the box思考问题的习惯。
            • 不敢不敢。
          • 这都那跟那啊? 我是偶然看到这页想到 volatile的
            • That bug explained the result of 2259.. I guess.. or maybe it is just coincidence
              • maybe it's the same kind of bug, just wandering how does the compiler deal with those code...
                • You can check C89 for official answer. This is about language standard question.
      • volatile 的意思是其值 可被 另一线程 或 硬件 随时改变。如果没有被改变, volatile变量和一般变量应该没有区别
    • 第一个不是5693吗?
      • 帮我看看我哪里错了吧
        main()
        {
        int x=20,y=35;
        x=y++ + x++;
        y= ++y + ++x;
        printf(“%d%d ”,x,y);

        }

        Step 1. calculate "y++", the result of the expression is 35 and y is 36;
        Step 2. calculate "x++", the result is 20 and x is 21;
        Step 3. calculate "(y++) + (x++)" (use results of the above 2 steps, the result is 35 + 20, i.e. 55.
        Step 4. assign 55 to x. Up to now x = 55 and y = 36.

        Step 5. calculate "++y", the result is 37 and y is 37.
        Step 6. calculate "++x", the result is 56 and x is 56
        Step 7. calculate "(++y) + (++x)", using the results of the above 2 steps, the result is 93.
        Step 8. assign 93 to y. Now x = 56 and y = 93.
        • seems
          step1: x = y + x; (55)
          step2; y = y+1; (36)
          step3; x= x+1; (56)

          step4: y= y+1; (37)
          step5: x=x+1; (57)
          step6:y=y+x; (94)
          • FYI: C Language Operator Precedence Chart
    • 如果是单线程,纯内存操作,我看不出有volatile 对第二题的影响。能请夏老师指点一下吗?
      • 第一个 #5421055@0的解释 和运算结果一致;2259 是第二个的运行结果; 在x86上,linux ,gcc编译运行的; 正抓狂想原因; 可惜x86汇编不熟;
        • 为什么要声明volatile?是不是被你贴出来的逻辑以外的东东改变了数值?那这里说什么都白搭。
          • completed code:
            #include "stdio.h"

            void func()
            {
            volatile int x=20, y=35;
            x=y++ + x++;
            y= ++y + ++x;
            printf("%d%d\n",x,y);

            }

            main()
            {

            func();

            }
            • I usually do not pay too much attention to complicated syntax skills, like macros, unless I have no choice. Here what concerns me most is the intention of declaring "volatile", if the 2 variables are not used by other threads or external devices.
        • 夏老弟,看汇编没用,找一本最新的C标准,好好读读operator precedence一节。
          俺现在太忙了,等下下星期闲下来,再给出标准答案。
          • hehe, here is the result #5422795@0
      • "如果是单线程,纯内存操作,我看不出有volatile 对第二题的影响" --- 能解释一下如果是多线程环境又会怎样?
        • 这个volatile就是告诉编译器,不要作任何优化,每次操作老老实实从内存把数值load到寄存器,避免多线程(中断 )间失步错误;
          • 谢谢,好久不用c, and embedded system, 脑子都简单了. 这可能是个有所帮助的link.
        • volatile variable:
          A volatile variable is one that can change unexpectedly. Consequently, the compiler can make no assumptions about the value of the variable. In particular, the optimizer must be careful to reload the variable every time it is used instead of holding a copy in a register. Examples of volatile variables are:

          * Hardware registers in peripherals (for example, status registers)
          * Non-automatic variables referenced within an interrupt service routine
          * Variables shared by multiple tasks in a multi-threaded application
          • humm. so my naive question is: If a variable is declared as volatile, all codes related with this variable will not be optimized by compiler, or, compiler simply shut off its optimization for all codes?
            • I don't know the compiler's behavior on this case. But I guess a goos compiler should optimize other parts of code that are not related to the volatile variables base on the options from the user.
    • Compiler dependant吧?俺估计得objdump后才能告诉你结果。不过出这种题目是吃饱了撑的。招人考这种题目还不如问人DMA要注意些啥来得实际。
      • 高人来了; (不是考题,正好遇到了)
        本文发表在 rolia.net 枫下论坛#include "stdio.h"

        void func()
        {
        volatile int x=20, y=35;
        x=y++ + x++;
        y= ++y + ++x;
        printf("%d%d\n",x,y);

        }

        main()
        {

        func();

        }

        ....
        080483c4 <func>:
        80483c4: 55 push %ebp
        80483c5: 89 e5 mov %esp,%ebp
        80483c7: 83 ec 28 sub $0x28,%esp
        80483ca: c7 45 fc 14 00 00 00 movl $0x14,-0x4(%ebp)
        80483d1: c7 45 f8 23 00 00 00 movl $0x23,-0x8(%ebp)
        80483d8: 8b 55 f8 mov -0x8(%ebp),%edx
        80483db: 8b 4d fc mov -0x4(%ebp),%ecx
        80483de: 8d 04 0a lea (%edx,%ecx,1),%eax
        80483e1: 89 45 fc mov %eax,-0x4(%ebp)
        80483e4: 8d 42 01 lea 0x1(%edx),%eax
        80483e7: 89 45 f8 mov %eax,-0x8(%ebp)
        80483ea: 8d 41 01 lea 0x1(%ecx),%eax
        80483ed: 89 45 fc mov %eax,-0x4(%ebp)
        80483f0: 8b 45 f8 mov -0x8(%ebp),%eax
        80483f3: 83 c0 01 add $0x1,%eax
        80483f6: 89 45 f8 mov %eax,-0x8(%ebp)
        80483f9: 8b 55 f8 mov -0x8(%ebp),%edx
        80483fc: 8b 45 fc mov -0x4(%ebp),%eax
        80483ff: 83 c0 01 add $0x1,%eax
        8048402: 89 45 fc mov %eax,-0x4(%ebp)
        8048405: 8b 45 fc mov -0x4(%ebp),%eax
        8048408: 8d 04 02 lea (%edx,%eax,1),%eax
        804840b: 89 45 f8 mov %eax,-0x8(%ebp)
        804840e: 8b 45 f8 mov -0x8(%ebp),%eax
        8048411: 8b 55 fc mov -0x4(%ebp),%edx
        8048414: 89 44 24 08 mov %eax,0x8(%esp)
        8048418: 89 54 24 04 mov %edx,0x4(%esp)
        804841c: c7 04 24 10 85 04 08 movl $0x8048510,(%esp)
        8048423: e8 d0 fe ff ff call 80482f8 <printf@plt>
        8048428: c9 leave
        8048429: c3 ret
        ...更多精彩文章及讨论,请光临枫下论坛 rolia.net
        • X86好长一段时间没工作过了。不是很熟。Coldfire及ARM反倒好一点。俺的意思是有些东西是C spec里没硬性规定一定要怎样的。所以不同的Compiler会有不同的编译方试,从而导致结果的不同。印象中volatile也是如此,C spec里也
          印象中volatile也是如此,C spec里也没说Compiler一定不能把它优化到Reg,Compiler仍可忽略volatile.另外你objdump还可以多dump一些东西出来吧。
          • 我是偶然遇到这个结果, 估计象猫哥蒙的---是compiler的bug, 象是相加的结果没有load到内存,可惜不会用汇编求证; 。。。 objdump 可以dump很多, 我特意写成func,好objdump分离问题;
          • objdump of second main. gcc (SUSE Linux) 4.3.2 [gcc-4_3-branch revision 141291] GNU objdump (GNU Binutils; openSUSE 11.1) 2.19
            本文发表在 rolia.net 枫下论坛est1: file format elf32-i386


            Disassembly of section .init:

            080482f4 <_init>:
            80482f4: 55 push %ebp
            80482f5: 89 e5 mov %esp,%ebp
            80482f7: 53 push %ebx
            80482f8: 83 ec 04 sub $0x4,%esp
            80482fb: e8 00 00 00 00 call 8048300 <_init+0xc>
            8048300: 5b pop %ebx
            8048301: 81 c3 f4 1c 00 00 add $0x1cf4,%ebx
            8048307: 8b 93 fc ff ff ff mov -0x4(%ebx),%edx
            804830d: 85 d2 test %edx,%edx
            804830f: 74 05 je 8048316 <_init+0x22>
            8048311: e8 1e 00 00 00 call 8048334 <__gmon_start__@plt>
            8048316: e8 e5 00 00 00 call 8048400 <frame_dummy>
            804831b: e8 00 02 00 00 call 8048520 <__do_global_ctors_aux>
            8048320: 58 pop %eax
            8048321: 5b pop %ebx
            8048322: c9 leave
            8048323: c3 ret

            Disassembly of section .plt:

            08048324 <__gmon_start__@plt-0x10>:
            8048324: ff 35 f8 9f 04 08 pushl 0x8049ff8
            804832a: ff 25 fc 9f 04 08 jmp *0x8049ffc
            8048330: 00 00 add %al,(%eax)
            ...

            08048334 <__gmon_start__@plt>:
            8048334: ff 25 00 a0 04 08 jmp *0x804a000
            804833a: 68 00 00 00 00 push $0x0
            804833f: e9 e0 ff ff ff jmp 8048324 <_init+0x30>

            08048344 <__libc_start_main@plt>:
            8048344: ff 25 04 a0 04 08 jmp *0x804a004
            804834a: 68 08 00 00 00 push $0x8
            804834f: e9 d0 ff ff ff jmp 8048324 <_init+0x30>

            08048354 <printf@plt>:
            8048354: ff 25 08 a0 04 08 jmp *0x804a008
            804835a: 68 10 00 00 00 push $0x10
            804835f: e9 c0 ff ff ff jmp 8048324 <_init+0x30>

            Disassembly of section .text:

            08048370 <_start>:
            8048370: 31 ed xor %ebp,%ebp
            8048372: 5e pop %esi
            8048373: 89 e1 mov %esp,%ecx
            8048375: 83 e4 f0 and $0xfffffff0,%esp
            8048378: 50 push %eax
            8048379: 54 push %esp
            804837a: 52 push %edx
            804837b: 68 b0 84 04 08 push $0x80484b0
            8048380: 68 c0 84 04 08 push $0x80484c0
            8048385: 51 push %ecx
            8048386: 56 push %esi
            8048387: 68 24 84 04 08 push $0x8048424
            804838c: e8 b3 ff ff ff call 8048344 <__libc_start_main@plt>
            8048391: f4 hlt
            8048392: 90 nop
            8048393: 90 nop
            8048394: 90 nop
            8048395: 90 nop
            8048396: 90 nop
            8048397: 90 nop
            8048398: 90 nop
            8048399: 90 nop
            804839a: 90 nop
            804839b: 90 nop
            804839c: 90 nop
            804839d: 90 nop
            804839e: 90 nop
            804839f: 90 nop

            080483a0 <__do_global_dtors_aux>:
            80483a0: 55 push %ebp
            80483a1: 89 e5 mov %esp,%ebp
            80483a3: 53 push %ebx
            80483a4: 83 ec 04 sub $0x4,%esp
            80483a7: 80 3d 14 a0 04 08 00 cmpb $0x0,0x804a014
            80483ae: 75 40 jne 80483f0 <__do_global_dtors_aux+0x50>
            80483b0: 8b 15 18 a0 04 08 mov 0x804a018,%edx
            80483b6: b8 18 9f 04 08 mov $0x8049f18,%eax
            80483bb: 2d 14 9f 04 08 sub $0x8049f14,%eax
            80483c0: c1 f8 02 sar $0x2,%eax
            80483c3: 8d 58 ff lea -0x1(%eax),%ebx
            80483c6: 39 da cmp %ebx,%edx
            80483c8: 73 1f jae 80483e9 <__do_global_dtors_aux+0x49>
            80483ca: 8d b6 00 00 00 00 lea 0x0(%esi),%esi
            80483d0: 8d 42 01 lea 0x1(%edx),%eax
            80483d3: a3 18 a0 04 08 mov %eax,0x804a018
            80483d8: ff 14 85 14 9f 04 08 call *0x8049f14(,%eax,4)
            80483df: 8b 15 18 a0 04 08 mov 0x804a018,%edx
            80483e5: 39 da cmp %ebx,%edx
            80483e7: 72 e7 jb 80483d0 <__do_global_dtors_aux+0x30>
            80483e9: c6 05 14 a0 04 08 01 movb $0x1,0x804a014
            80483f0: 83 c4 04 add $0x4,%esp
            80483f3: 5b pop %ebx
            80483f4: 5d pop %ebp
            80483f5: c3 ret
            80483f6: 8d 76 00 lea 0x0(%esi),%esi
            80483f9: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi

            08048400 <frame_dummy>:
            8048400: 55 push %ebp
            8048401: 89 e5 mov %esp,%ebp
            8048403: 83 ec 08 sub $0x8,%esp
            8048406: a1 1c 9f 04 08 mov 0x8049f1c,%eax
            804840b: 85 c0 test %eax,%eax
            804840d: 74 12 je 8048421 <frame_dummy+0x21>
            804840f: b8 00 00 00 00 mov $0x0,%eax
            8048414: 85 c0 test %eax,%eax
            8048416: 74 09 je 8048421 <frame_dummy+0x21>
            8048418: c7 04 24 1c 9f 04 08 movl $0x8049f1c,(%esp)
            804841f: ff d0 call *%eax
            8048421: c9 leave
            8048422: c3 ret
            8048423: 90 nop

            08048424 <main>:
            8048424: 8d 4c 24 04 lea 0x4(%esp),%ecx
            8048428: 83 e4 f0 and $0xfffffff0,%esp
            804842b: ff 71 fc pushl -0x4(%ecx)
            804842e: 55 push %ebp
            804842f: 89 e5 mov %esp,%ebp
            8048431: 51 push %ecx
            8048432: 83 ec 24 sub $0x24,%esp
            8048435: c7 45 f8 14 00 00 00 movl $0x14,-0x8(%ebp)
            804843c: c7 45 f4 23 00 00 00 movl $0x23,-0xc(%ebp)
            8048443: 8b 55 f4 mov -0xc(%ebp),%edx
            8048446: 8b 4d f8 mov -0x8(%ebp),%ecx
            8048449: 8d 04 0a lea (%edx,%ecx,1),%eax
            804844c: 89 45 f8 mov %eax,-0x8(%ebp)
            804844f: 8d 42 01 lea 0x1(%edx),%eax
            8048452: 89 45 f4 mov %eax,-0xc(%ebp)
            8048455: 8d 41 01 lea 0x1(%ecx),%eax
            8048458: 89 45 f8 mov %eax,-0x8(%ebp)
            804845b: 8b 45 f4 mov -0xc(%ebp),%eax
            804845e: 83 c0 01 add $0x1,%eax
            8048461: 89 45 f4 mov %eax,-0xc(%ebp)
            8048464: 8b 55 f4 mov -0xc(%ebp),%edx
            8048467: 8b 45 f8 mov -0x8(%ebp),%eax
            804846a: 83 c0 01 add $0x1,%eax
            804846d: 89 45 f8 mov %eax,-0x8(%ebp)
            8048470: 8b 45 f8 mov -0x8(%ebp),%eax
            8048473: 8d 04 02 lea (%edx,%eax,1),%eax
            8048476: 89 45 f4 mov %eax,-0xc(%ebp)
            8048479: 8b 45 f4 mov -0xc(%ebp),%eax
            804847c: 8b 55 f8 mov -0x8(%ebp),%edx
            804847f: 89 44 24 08 mov %eax,0x8(%esp)
            8048483: 89 54 24 04 mov %edx,0x4(%esp)
            8048487: c7 04 24 70 85 04 08 movl $0x8048570,(%esp)
            804848e: e8 c1 fe ff ff call 8048354 <printf@plt>
            8048493: b8 00 00 00 00 mov $0x0,%eax
            8048498: 83 c4 24 add $0x24,%esp
            804849b: 59 pop %ecx
            804849c: 5d pop %ebp
            804849d: 8d 61 fc lea -0x4(%ecx),%esp
            80484a0: c3 ret
            80484a1: 90 nop
            80484a2: 90 nop
            80484a3: 90 nop
            80484a4: 90 nop
            80484a5: 90 nop
            80484a6: 90 nop
            80484a7: 90 nop
            80484a8: 90 nop
            80484a9: 90 nop
            80484aa: 90 nop
            80484ab: 90 nop
            80484ac: 90 nop
            80484ad: 90 nop
            80484ae: 90 nop
            80484af: 90 nop

            080484b0 <__libc_csu_fini>:
            80484b0: 55 push %ebp
            80484b1: 89 e5 mov %esp,%ebp
            80484b3: 5d pop %ebp
            80484b4: c3 ret
            80484b5: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
            80484b9: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi

            080484c0 <__libc_csu_init>:
            80484c0: 55 push %ebp
            80484c1: 89 e5 mov %esp,%ebp
            80484c3: 57 push %edi
            80484c4: 56 push %esi
            80484c5: 53 push %ebx
            80484c6: e8 4f 00 00 00 call 804851a <__i686.get_pc_thunk.bx>
            80484cb: 81 c3 29 1b 00 00 add $0x1b29,%ebx
            80484d1: 83 ec 0c sub $0xc,%esp
            80484d4: e8 1b fe ff ff call 80482f4 <_init>
            80484d9: 8d bb 18 ff ff ff lea -0xe8(%ebx),%edi
            80484df: 8d 83 18 ff ff ff lea -0xe8(%ebx),%eax
            80484e5: 29 c7 sub %eax,%edi
            80484e7: c1 ff 02 sar $0x2,%edi
            80484ea: 85 ff test %edi,%edi
            80484ec: 74 24 je 8048512 <__libc_csu_init+0x52>
            80484ee: 31 f6 xor %esi,%esi
            80484f0: 8b 45 10 mov 0x10(%ebp),%eax
            80484f3: 89 44 24 08 mov %eax,0x8(%esp)
            80484f7: 8b 45 0c mov 0xc(%ebp),%eax
            80484fa: 89 44 24 04 mov %eax,0x4(%esp)
            80484fe: 8b 45 08 mov 0x8(%ebp),%eax
            8048501: 89 04 24 mov %eax,(%esp)
            8048504: ff 94 b3 18 ff ff ff call *-0xe8(%ebx,%esi,4)
            804850b: 83 c6 01 add $0x1,%esi
            804850e: 39 fe cmp %edi,%esi
            8048510: 72 de jb 80484f0 <__libc_csu_init+0x30>
            8048512: 83 c4 0c add $0xc,%esp
            8048515: 5b pop %ebx
            8048516: 5e pop %esi
            8048517: 5f pop %edi
            8048518: 5d pop %ebp
            8048519: c3 ret

            0804851a <__i686.get_pc_thunk.bx>:
            804851a: 8b 1c 24 mov (%esp),%ebx
            804851d: c3 ret
            804851e: 90 nop
            804851f: 90 nop

            08048520 <__do_global_ctors_aux>:
            8048520: 55 push %ebp
            8048521: 89 e5 mov %esp,%ebp
            8048523: 53 push %ebx
            8048524: 83 ec 04 sub $0x4,%esp
            8048527: a1 0c 9f 04 08 mov 0x8049f0c,%eax
            804852c: 83 f8 ff cmp $0xffffffff,%eax
            804852f: 74 13 je 8048544 <__do_global_ctors_aux+0x24>
            8048531: bb 0c 9f 04 08 mov $0x8049f0c,%ebx
            8048536: 66 90 xchg %ax,%ax
            8048538: 83 eb 04 sub $0x4,%ebx
            804853b: ff d0 call *%eax
            804853d: 8b 03 mov (%ebx),%eax
            804853f: 83 f8 ff cmp $0xffffffff,%eax
            8048542: 75 f4 jne 8048538 <__do_global_ctors_aux+0x18>
            8048544: 83 c4 04 add $0x4,%esp
            8048547: 5b pop %ebx
            8048548: 5d pop %ebp
            8048549: c3 ret
            804854a: 90 nop
            804854b: 90 nop

            Disassembly of section .fini:

            0804854c <_fini>:
            804854c: 55 push %ebp
            804854d: 89 e5 mov %esp,%ebp
            804854f: 53 push %ebx
            8048550: 83 ec 04 sub $0x4,%esp
            8048553: e8 00 00 00 00 call 8048558 <_fini+0xc>
            8048558: 5b pop %ebx
            8048559: 81 c3 9c 1a 00 00 add $0x1a9c,%ebx
            804855f: e8 3c fe ff ff call 80483a0 <__do_global_dtors_aux>
            8048564: 59 pop %ecx
            8048565: 5b pop %ebx
            8048566: c9 leave
            8048567: c3 ret更多精彩文章及讨论,请光临枫下论坛 rolia.net
        • 翻译成c是这样子的
          本文发表在 rolia.net 枫下论坛080483c4 <func>:
          80483c4: 55 push %ebp
          80483c5: 89 e5 mov %esp,%ebp
          80483c7: 83 ec 28 sub $0x28,%esp
          80483ca: c7 45 fc 14 00 00 00 movl $0x14,-0x4(%ebp) //x=20
          80483d1: c7 45 f8 23 00 00 00 movl $0x23,-0x8(%ebp) //y=35
          80483d8: 8b 55 f8 mov -0x8(%ebp),%edx
          80483db: 8b 4d fc mov -0x4(%ebp),%ecx //ecx=x=20
          80483de: 8d 04 0a lea (%edx,%ecx,1),%eax
          80483e1: 89 45 fc mov %eax,-0x4(%ebp)//x=x+y=55

          80483e4: 8d 42 01 lea 0x1(%edx),%eax
          80483e7: 89 45 f8 mov %eax,-0x8(%ebp)//y=y+1=36
          // 问题在这里,“x”不是从内存里面重新读出来的x的值,而是直接用了寄存器ecx,所以不是55而是20。前面好像少了一条指令: 8b 4d fc mov -0x4(%ebp),%ecx 像是个编译器bug.
          80483ea: 8d 41 01 lea 0x1(%ecx),%eax
          80483ed: 89 45 fc mov %eax,-0x4(%ebp)//x=“x”+1=21
          //
          80483f0: 8b 45 f8 mov -0x8(%ebp),%eax
          80483f3: 83 c0 01 add $0x1,%eax
          80483f6: 89 45 f8 mov %eax,-0x8(%ebp)//y=y+1=36+1=37

          80483f9: 8b 55 f8 mov -0x8(%ebp),%edx //edx = y = 37

          80483fc: 8b 45 fc mov -0x4(%ebp),%eax
          80483ff: 83 c0 01 add $0x1,%eax
          8048402: 89 45 fc mov %eax,-0x4(%ebp) //x=x+1=22

          8048405: 8b 45 fc mov -0x4(%ebp),%eax
          8048408: 8d 04 02 lea (%edx,%eax,1),%eax
          804840b: 89 45 f8 mov %eax,-0x8(%ebp)//y=x+y=22+37=59

          //下面是打印
          804840e: 8b 45 f8 mov -0x8(%ebp),%eax
          8048411: 8b 55 fc mov -0x4(%ebp),%edx
          8048414: 89 44 24 08 mov %eax,0x8(%esp)
          8048418: 89 54 24 04 mov %edx,0x4(%esp)
          804841c: c7 04 24 10 85 04 08 movl $0x8048510,(%esp)
          8048423: e8 d0 fe ff ff call 80482f8 <printf@plt>
          8048428: c9 leave
          8048429: c3 ret更多精彩文章及讨论,请光临枫下论坛 rolia.net
          • 对呀! 高人啊。和我蒙的是一致的 :-) #5422795@0 and #5423300@0
    • 都很努力学习嘛, 夜校啊?
      • 夏老师的贴,一定要捧场的。
        • 都是能人, 佩服佩服
          • 我现在准备混在事业版和牛哥,猫哥,车哥,忘情水哥学习了; :-)
            • 哈哈,把我与事业版的大腕列在一对了,荣幸!谢谢夏老师提携!
              • 都挺能起哄. 我能在这里当学生嘛?
                • 当冰哥。在这里没有客气的。
                  • 冰歌,好听些
                    • bingo
          • 对了,我原来的大号就叫哄哥,应是被你们整成了什么“夏老师”
        • 多谢,多谢; 回头再发一帖,多多帮忙;
    • 我看了这贴不回不行。编程的要领是什么?3R(自己Google去)。可读性是非常重要的。我编写了22年程序,重来都以可读性为上,这样其他人也好跟进你的程序。若我看到其他人写出搂主题目这样含糊不清故弄玄虚的程序,我立马叫他重编,若他不重编,立马赶人。
      • 同感。不是干活是玩人呢。
        • 痛感.
          • 谔谔锷,这词可不能瞎说,痛并快乐着
      • +1. LZ在逗着玩呢
      • 哎! 又来一个当领导的; 怎么都不喜欢具体分析问题解决问题呢?
        • NO,至今我还不是领导,因为我不爱走领导这路,但我是SMTS(指个人技术上的职位)。我的老板很听我的意见(比如面试评价或赶人走)。至于你的具体分析问题解决问题请见内。
          第一段,按你的程序输出应该是5794,而不是"94 57"(#5421055),你居然还说人家对(#5421085)?
          你若把程序写成以下这样,估计99%的人都能正确解答。
          main()
          {
          int x=20,y=35;

          x=y+x;
          y++;
          x++;

          ++y;
          ++x;
          y=y+x;

          printf("%d%d",x,y);
          }

          第二段,volatile适用于其他程序如中断程序可能会修改的变量。你现在的程序根本就不能很好的利用到volatile的好处,因为x和y都在堆栈里,地址是动态的,其他程序如中断程序很难知道到x和y在哪.你真想要利用到volatile的好处,就应该把volatile x,y放到全局变量处。
          若单看你的程序,假设运行main()时没有任何其它程序修改x和y,结果就应该和没有volatile一样。有人已经提到实际运行结果在Linux中是2259,我也证实了此不可思议的结果。归根结底就是这段程序设计含糊不清,不同编译器有不同结果。若你改成以下代码,则在任何c编译器下的结果和第一段相同 5794(也得假设运行main()时没有任何其它程序修改x和y)
          main()
          {
          volatile int x=20,y=35;

          x=y+x;
          y++;
          x++;

          ++y;
          ++x;
          y=y+x;

          printf("%d%d",x,y);
          }
          • +1....
          • 贴这个题时, 就没把他当成coding style issue; 想问的就是编译器的行为; 您的分析,简单化为coding风格不妥,绕开了原来的关键点,所以问题没得到解决;
            基于这样的考虑, "94 57"(#5421055),给出了编译器的行为和结果,就可以认为对了,这个上贴错序的小错是一目了然的,大家都明白,不用在这种细枝末节上纠缠了;

            volatile x,y放到全局变量处或自动变量在这里对编译器的行为没有影响;这样写的目的是用简单的方法敏化问题;

            上面的讨论中很多大侠提到了编译器问题,这是解决问题的关键思路;看看上面的反汇编,应该能得到具体的解释;

            另外,绕开了根本问题,指责原问题问得幼稚或错误, 这个解决“问题”的方法我以前用过, 没用; 对解决问题或增加自己的credit都没用; 不管说自己是SMTS,或CTO,全没用;
      • 华人小公司的技术骨干?谁要是不听你的,立马赶人?这就是贵公司的企业文化?这种公司,不用赶,有点本事的都不会在那里混。有你这样的小头头,算你那些同事倒霉。
      • 换个角度说,虽然不推荐代码写成这样,但是你最好能看懂,所以俺们这里讨论讨论是必要的 - 当然,这是理论上说。实际上,我还没见过哪个real project中出现过类似的代码,程序员们还是有点common sense的。。。一般会让它易读一点,因为他们也不想自己日后费脑子。。。
    • 俺以务实的精神讲,答案是57,94和56,93。AIX Polymake下 编译并执行。
      • fair enough
    • Actually the root cause is x= y++ + x++, which behavior according to c standard is undefined, so it just happens to be the output you expect in case of without volatile keyword.
      • good to know. thx
      • without the volatile, though the x = y++ + x++ could be handled differenly by different compiler, but the results are same.
    • why is 2259?
      本文发表在 rolia.net 枫下论坛一个简单的问题, 答案是56 93, 或是57 94 似乎都make sense.应为这是是和编译器相关的问题;

      昨天顺手加上 volatile 希望关掉优化编译, 但得到 2259的结果是无论无何都不应该算对的; 才贴上了这个问题;

      各位侠哥都意识到编译器相关,或标准相关,但有些忽略这是个不能接受的结果;
      忘情水哥概念入手, 坚持真理,直逼问题核心,思路正确;
      猫哥艺高人胆大, google一把,就蒙对了答案------- 编译器在此处出错了!!


      咱也google 一下 X86 汇编指令, 分析错误原因如下:
      #include "stdio.h"

      void func()
      {
      volatile int x=20, y=35;
      x=y++ + x++;
      y= ++y + ++x;
      printf("%d%d ",x,y);

      }

      main()
      {

      func();

      }

      ....
      080483c4 <func>:
      80483c4: 55 push %ebp <----- push stack
      80483c5: 89 e5 mov %esp,%ebp <------ point to top of stack
      80483c7: 83 ec 28 sub $0x28,%esp <----- allocate stack space why is 0x28 i don't know
      80483ca: c7 45 fc 14 00 00 00 movl $0x14,-0x4(%ebp) <--- now we confirmed offset 0x4 is x memory space
      80483d1: c7 45 f8 23 00 00 00 movl $0x23,-0x8(%ebp) <---- offset 0x8 is y memory space
      80483d8: 8b 55 f8 mov -0x8(%ebp),%edx <------load Y to register edx
      80483db: 8b 4d fc mov -0x4(%ebp),%ecx <------- load X to register ecx
      80483de: 8d 04 0a lea (%edx,%ecx,1),%eax <----- reg eax = edx( y value) + ecx(x value) + 1 (?)
      80483e1: 89 45 fc mov %eax,-0x4(%ebp) <---- reg eax load to X memory space( correct here )....
      80483e4: 8d 42 01 lea 0x1(%edx),%eax <----- eax = edx + 1
      80483e7: 89 45 f8 mov %eax,-0x8(%ebp) <------- reg eax load to Y memory space (valie y++)
      80483ea: 8d 41 01 lea 0x1(%ecx),%eax <------eax = ecx + 1; (value 20 +1 )
      80483ed: 89 45 fc mov %eax,-0x4(%ebp) <-------- load to X memory again !!!!!!!!! wrong..!!!!!!!
      80483f0: 8b 45 f8 mov -0x8(%ebp),%eax
      80483f3: 83 c0 01 add $0x1,%eax
      80483f6: 89 45 f8 mov %eax,-0x8(%ebp)
      80483f9: 8b 55 f8 mov -0x8(%ebp),%edx
      80483fc: 8b 45 fc mov -0x4(%ebp),%eax
      80483ff: 83 c0 01 add $0x1,%eax
      8048402: 89 45 fc mov %eax,-0x4(%ebp)
      8048405: 8b 45 fc mov -0x4(%ebp),%eax
      8048408: 8d 04 02 lea (%edx,%eax,1),%eax
      804840b: 89 45 f8 mov %eax,-0x8(%ebp)
      804840e: 8b 45 f8 mov -0x8(%ebp),%eax
      8048411: 8b 55 fc mov -0x4(%ebp),%edx
      8048414: 89 44 24 08 mov %eax,0x8(%esp)
      8048418: 89 54 24 04 mov %edx,0x4(%esp)
      804841c: c7 04 24 10 85 04 08 movl $0x8048510,(%esp)
      8048423: e8 d0 fe ff ff call 80482f8 <printf@plt>
      8048428: c9 leave
      8048429: c3 ret
      ...
      <本文发表于: 相约加拿大:枫下论坛 www.rolia.net/forum >更多精彩文章及讨论,请光临枫下论坛 rolia.net
      • "google一把,就蒙对了答案".. LOL..不会编程,还是会google的。
      • lea (%edx,%ecx,1),%eax = ecx * 1 + edx -> eax.
        • ok. thx; this addresses my confusion here. compiler should load the X value into register again before do X++, which is exactly volatile supposed to do.
          • 刚才在Cygwin的gcc上面试了一下, 发现gcc还是牛多了,hehe
            • 结果是什么呀?
              • 5693
              • 比较搞的是我把你的第一个func放上去想比较一下生成的汇编有啥区别, 结果被gcc优化成这个样子:
                pushl %ebp
                movl $94, %edx
                movl %esp, %ebp
                movl $57, %eax
                subl $24, %esp
                movl %edx, 8(%esp)
                movl %eax, 4(%esp)
                movl $LC0, (%esp)
                call _printf
                leave
                ret
                • 真是有钱有闲又有权啊.我实在没有精力研究这个问题.C还没有认全.
    • 好象没有标准答案,不同编译器有不同的实现(没查C标准,不十分肯定)。俺的理解,下面两个答案都应该是正确的:
      Without volatile:

      int x = 20, y = 35;
      x = y + x;
      x++;
      y++;
      ++y;
      ++x;
      y = y + x;

      Results are (57, 94)

      Or

      int x = 20, y = 35;
      register A = y + x;
      x++; // this increment will be discarded later
      y++;
      x = register A; // x <-- 55
      ++y;
      ++x;
      y = y + x;

      Results are (56, 93)
      • 加上volatile 限定词之后,又多了一种可能:
        volatile int x = 20;
        volatile int y = 35;
        reg X <-- x;
        reg Y <-- y;
        reg Z = reg Y + reg X;
        x <-- reg Z;
        reg X++;
        reg Y++;
        x <-- reg X; // the writeback happens because x is volatile. x == 21 here !
        y <-- reg Y;

        问题的关键在 x = y++ + x++; 一句,x赋值在先,还是加1在先,C标准有明确的规定吗?
      • no, 5693 should be
        x=x+y
        y++
        x++
        y=x+y
        x++
        y++

        this increment can not be discarded later, it's compiler error again otherwise;
      • 按照操作符优先权来解释这段程序,只有一个答案,5794,没有歧义。得出不同结果的编译器有bug,至少是没有严格遵守C标准。
    • 参考答案
      看了大家的回复,我作为半个电脑工程师,不知道该跟大家说什么好。先公布一下参考答案。
      本答案是手算结果,大家可以用电脑校验一下。
      build without -O:
      both are the same results as:x=57. y=94.

      build with -O2 or -O2:
      seconds result is: x=57. y=94.
      first result is: x=22 y=59

      本人今年年底将失业。如果大家有工作,介绍一下。
      • 上面讨论很充分了,编译器相关, x=22 y=59的结果应该是编译器的bug造成的。
      • 年底还早着呢,找新工作应该没问题的; :-)
    • volatile + x=x + optimization 真可怕
    • 我来回答这个问题:在C(或者C++)语言的标准里,有一个概念称为sequence point,请进来看……
      本文发表在 rolia.net 枫下论坛  C语言1999年标准(ISO-IEC 9899:1999)的第十三页:

      Evaluation of an expression may produce side effects. At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.

      In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).

        那就是说,一个表达式中,可以被若干个sequence points分成几个小段(可以称之为子表达式)。在一个子表达式内,如何计算side effects是不确定的,不同的编译器可以采用不同的方法和运算次序。

        但是,在表达式的计算到达任何一个sequence point 的时刻,在这个sequence point 之前的子表达式的所有的side effects必须全部计算完毕。

        那么,哪些点是sequence point 呢?第四百三十七页:

      — The call to a function, after the arguments have been evaluated.

      — The end of the first operand of the following operators: logical AND &&; logical OR ||; conditional ?; comma ,.

      — The end of a full declarator: declarators;

      — The end of a full expression: an initializer; the expression in an expression statement; the controlling expression of a selection statement (if or switch); the controlling expression of a while or do statement (6.8.5); each of the expressions of a for statement (6.8.5.3); the expression in a return statement.

      — Immediately before a library function returns.

      — After the actions associated with each formatted input / output function conversion specifier.

      — Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call.

        看几个例子:

        a = ++a;

        a的值不确定。

        if( a++ != 0 || b[a] > 5 ) ...

        布尔表达式的值确定,因为“||”是一个sequence point。更多精彩文章及讨论,请光临枫下论坛 rolia.net