Chinaunix

标题: 此题何解?求高人指点 [打印本页]

作者: dingning239    时间: 2011-03-21 11:18
标题: 此题何解?求高人指点
#include <stdio.h>
#include <conio.h>

main ()
{   
     
   int j,i = 5;
    j = (++i)+(--i)-(--i);
    printf("j is :%d,i is :%d\n",j, i);
    getch();
}   


谁知道这里的 j ,i 的值,希望不要通过运行来看结果
作者: egmkang    时间: 2011-03-21 11:23
It’s beyond me .
作者: hellioncu    时间: 2011-03-21 11:27
无聊的题
作者: cobras    时间: 2011-03-21 11:37
possible result
i=4,j=12
undefined behavior
作者: L_kernel    时间: 2011-03-21 11:56
6 + 5 - 4
j = 7
i = 4
不知道有没有错,跟实际平台和环境有关系。
作者: pmerofc    时间: 2011-03-21 12:22
提示: 作者被禁止或删除 内容自动屏蔽
作者: goldenfort    时间: 2011-03-21 12:38
回复 1# dingning239


    你如果觉得数汉字的笔顺有意义, 就好地做这样的题目吧
作者: dingning239    时间: 2011-03-21 12:39
这样的代码本身就是错的,没有意义
pmerofc 发表于 2011-03-21 12:22



    这我在编译以后运行是有结果的,你运行过么就说代码错
作者: dingning239    时间: 2011-03-21 12:39
6 + 5 - 4
j = 7
i = 4
不知道有没有错,跟实际平台和环境有关系。
L_kernel 发表于 2011-03-21 11:56



    i 确实是 4,但是 j 不是7
作者: dingning239    时间: 2011-03-21 12:40
无聊的题
hellioncu 发表于 2011-03-21 11:27



    拜托:觉得无聊的话,你可以不看,这样的灌水没意义
作者: dingning239    时间: 2011-03-21 12:42
回复 7# goldenfort


    我只想知道结果,谢谢,其他不想讨论
作者: dingning239    时间: 2011-03-21 12:44
possible result
i=4,j=12
undefined behavior
cobras 发表于 2011-03-21 11:37



    i 确实是 4,但 j 不是 12
作者: L_kernel    时间: 2011-03-21 12:45
i 确实是 4,但是 j 不是7
dingning239 发表于 2011-03-21 12:39
运行的结果:
j is : 6, i is : 4
作者: L_kernel    时间: 2011-03-21 12:45
这我在编译以后运行是有结果的,你运行过么就说代码错
dingning239 发表于 2011-03-21 12:39
他可能是说逻辑上的错误,没有人在实际当中会这样子些代码的。不是语法上面的错误。
作者: dingning239    时间: 2011-03-21 12:48
回复 13# L_kernel


    有结果不能说明代码有问题吧,像这样啥都不看就说有问题的,这样的回复没意义
作者: pmerofc    时间: 2011-03-21 12:52
提示: 作者被禁止或删除 内容自动屏蔽
作者: dingning239    时间: 2011-03-21 12:53
回复 16# pmerofc


    如果你认为有错误,请指出错误的所在,谢谢
作者: pmerofc    时间: 2011-03-21 12:54
提示: 作者被禁止或删除 内容自动屏蔽
作者: pmerofc    时间: 2011-03-21 12:55
提示: 作者被禁止或删除 内容自动屏蔽
作者: pmerofc    时间: 2011-03-21 12:56
提示: 作者被禁止或删除 内容自动屏蔽
作者: dingning239    时间: 2011-03-21 12:59
回复 19# pmerofc


    有待考证
作者: egmkang    时间: 2011-03-21 13:06
没有结果的....
如果有结果,结果只有一个,这样的代码没有任何意义,都有副作用了,而且还把他当数学公式了??

C里面没有对求值顺序做假设,换句话说,你爱怎么求值怎么求值,都是满足标准的.
作者: dingning239    时间: 2011-03-21 13:17
没有结果的....
如果有结果,结果只有一个,这样的代码没有任何意义,都有副作用了,而且还把他当数学公式了?? ...
egmkang 发表于 2011-03-21 13:06


通过编译,运行的结果

i=4 j=6

    我想知道的是这个6是如何算出来的,如果您知道的话,请不吝赐教!
作者: egmkang    时间: 2011-03-21 13:26
通过编译,运行的结果

i=4 j=6

    我想知道的是这个6是如何算出来的,如果您知道的话,请不吝赐 ...
dingning239 发表于 2011-03-21 13:17


数学里面的求值,没有顺序之说,因为他是没有副作用的,输入A,输出必然是B.
但是在程序语言中(C/C++之类),很多代码都是有副作用的,比如你这个++,--.
然后你要是拿着数学公式里面的思想去理解程序语言,必然会产生一些错觉.

expression=expressionA + expressionB
在C语言里面依赖expressionA和expressionB的求值顺序,换句话说,expression=expressionB +expressionA 和上面那个表达式不是等价的.
如果这里面每个expression都没有副作用,那么expression的值就是一定的;如果有副作用,值未知.

而你的++,--,都是有副作用的表达式,expression的结果必然依赖求值顺序~!@#$%^&*()_+

上帝知道答案是多少!
作者: dingning239    时间: 2011-03-21 13:32
数学里面的求值,没有顺序之说,因为他是没有副作用的,输入A,输出必然是B.
但是在程序语言中(C/C++之类) ...
egmkang 发表于 2011-03-21 13:26



    副作用,您给讲讲我这个表达式中的副作用是啥?
作者: egmkang    时间: 2011-03-21 13:34
你如果真的想知道答案,可以尝试着这么做.
j = (++i)+(--i)-(--i);
你换成
tempA = ++i;
tempB = --i;
tempC = --i;

j = tempA + tempB - tempC;

然后三个第四个表达式没副作用,前面三个都有,3的全排列是6,你试着交换A,B,C的顺序,看看6种排列结果,J的值一共有多少个.
编译器的答案一般都在这些值中
作者: egmkang    时间: 2011-03-21 13:36
副作用,您给讲讲我这个表达式中的副作用是啥?
dingning239 发表于 2011-03-21 13:32


副作用很好理解的
exp = expA
多次执行,exp的值是不变的,那么我们就说这个exp = expA没副作用的;
如果不是,那么就说这个表达式有副作用
作者: dingning239    时间: 2011-03-21 13:46
副作用很好理解的
exp = expA
多次执行,exp的值是不变的,那么我们就说这个exp = expA没副作用的;
如 ...
egmkang 发表于 2011-03-21 13:36



   
您说的是如果值不是确定的话就是存在副作用,如果确定的则不是,但是此表达式每次计算出来的结果无一例外都是 6 ,这又如何解释不确定性呢?
作者: egmkang    时间: 2011-03-21 13:52
您说的是如果值不是确定的话就是存在副作用,如果确定的则不是,但是此表达式每次计算出来的结 ...
dingning239 发表于 2011-03-21 13:46


我勒个去...
我跟你没办法沟通....
作者: dingning239    时间: 2011-03-21 13:56
我勒个去...
我跟你没办法沟通....
egmkang 发表于 2011-03-21 13:52



    无语,看来这个问题还得高人解答了,期待中。。。
作者: rover12421    时间: 2011-03-21 13:59
回复 28# dingning239

j = (++i)+(--i)-(--i)+(++i)+(--i)-(--i);
这个j会等于12吗?
j = (++i)+(--i)-(--i)-(++i)+(--i)-(--i);
这个j会等于0吗?

再看看这两个
((++i)+(--i)-(--i))+((++i)+(--i)-(--i))
((++i)+(--i)-(--i))-((++i)+(--i)-(--i))


您觉得这有意义嘛
作者: dingning239    时间: 2011-03-21 14:01
回复  dingning239

j = (++i)+(--i)-(--i)+(++i)+(--i)-(--i);
这个j会等于12吗?
j = (++i)+(--i)-( ...
rover12421 发表于 2011-03-21 13:59



    这样的计算我理解不了,我只想知道6是如何计算出来的?如果您知道,请详细说说,不胜感激
作者: tubocurarine    时间: 2011-03-21 14:49
以前有人很详细的解释过这个问题,想要了解这个问题,要知道什么是 序列点。参见:
C FAQ 3.2, 3.8. 3.11

http://www.is.pku.edu.cn/~qzy/c/c_faq/c-faq03.txt
作者: 吴秦    时间: 2011-03-21 14:59
回复 1# dingning239


    j=6, i=4
这中类似的表达式我曾经研究过,具体参考我的博客http://www.cnblogs.com/skynet/archive/2010/07/11/1775084.html,耐心看完对你应该有帮助!
作者: madoldman    时间: 2011-03-21 15:20
回复 32# dingning239
既然是个未定义行为,当然是编译器自己想怎么弄就怎么弄的。因为你的编译器恰好能弄出这么个值来而已,换个其他的编译器,弄出个其他的值来也不奇怪。
弄个变态的编译器,看到这样的语句,格式化你的硬盘,也是符合标准的,这就是未定义。都未定义了,你还去追它为什么有意思吗?
作者: mpstat    时间: 2011-03-21 17:07
回复 30# dingning239

..别人耐心的给你讲那么久你怎么就是听不进去呢,你只是在一台机器的一种编译器上反复的编译运行,这有个屁的测试效果啊.

你要么换些操作系统,换些编译器换些优化参数之类的再做测试,要么不要在这里死撑非要别人给你讲道理.别人讲得清清楚楚你说你不懂还要求高人解释
作者: mdou1986    时间: 2011-03-21 17:16
难道i是4,j是6?
作者: pmerofc    时间: 2011-03-21 17:49
提示: 作者被禁止或删除 内容自动屏蔽
作者: dawnless    时间: 2011-03-21 19:33
LZ最好先看下 未定义的行为 是什么意思。
作者: wb112200    时间: 2011-03-21 19:54
It’s beyond me .
作者: hardie    时间: 2011-03-22 09:07
j = (((++i) + (--i)) - (--i));
作者: pmerofc    时间: 2011-03-22 09:18
提示: 作者被禁止或删除 内容自动屏蔽
作者: leolzbing521    时间: 2011-03-22 14:24
用gdb调试跟踪不错来吗?
作者: churchmice    时间: 2011-03-22 15:30
回复 1# dingning239


你这问题真是对不起你的头像啊,还搞得很求是一样,自己错了就承认,不要再这么折腾下去了,没意思
作者: hebingyue    时间: 2011-03-22 16:20
  1.   1     .file   "m.c"
  2.   2     .section    .rodata
  3.   3 .LC0:
  4.   4     .string "j is :%d,i is :%d\n"
  5.   5     .text
  6.   6 .globl main
  7.   7     .type   main, @function
  8.   8 main:
  9.   9     pushl   %ebp
  10. 10     movl    %esp, %ebp
  11. 11     andl    $-16, %esp
  12. 12     subl    $32, %esp
  13. 13     movl    $5, 28(%esp)
  14. 14     addl    $1, 28(%esp)
  15. 15     subl    $1, 28(%esp)
  16. 16     movl    28(%esp), %eax
  17. 17     addl    %eax, %eax
  18. 18     subl    $1, 28(%esp)
  19. 19     subl    28(%esp), %eax
  20. 20     movl    %eax, 24(%esp)
  21. 21     movl    $.LC0, %eax
  22. 22     movl    28(%esp), %edx
  23. 23     movl    %edx, 8(%esp)
  24. 24     movl    24(%esp), %edx
  25. 25     movl    %edx, 4(%esp)
  26. 26     movl    %eax, (%esp)
  27. 27     call    printf
  28. 28     call    getchar
  29. 29     leave
  30. 30     ret
  31. 31     .size   main, .-main


  32.   1 #include <stdio.h>
  33.   2
  34.   3 int main ()
  35.   4 {
  36.   5
  37.   6     int j,i = 5;
  38.   7     j = (++i)+(--i)-(--i);
  39.   8     printf("j is :%d,i is :%d\n",j, i);
  40.   9     getchar();
  41. 10 }
  42. ~                  
  43. 汇编代码分析:
  44.   13     movl    $5, 28(%esp)   ==》 i = 5; 这里的28(%esp)就是堆栈偏移28,也就是局部变量i
  45.   14     addl    $1, 28(%esp)   ==>  ++i;
  46.   15     subl    $1, 28(%esp)   ==>  --i;
  47.   到这里i的结果是5,也是符合我们预期的。
  48.   接下来就不是我们想看到的,
  49.   16     movl    28(%esp), %eax
  50.   17     addl    %eax, %eax     
  51.   gcc编译器,把++i 和 --i的结果都放在堆栈28(%esp)同一个位置上,
  52.   代码17行,就相当于 5+5 ==》10, 我们预期的是11
  53.   然后subl    $1, 28(%esp),再减1, ==》 i==4
  54.   那得到 j = 10 - 4, 当然结果就是6啦。

  55.   所以说不要在同一个点上改变一个变量两次及以上,不然会得到你不想要的结果。
  56.   声明:本人汇编不熟悉,临时看了下汇编语法分析的,有不对的地方,请指出。
  57.   
  58.   
  59.   
  60.   
  61.   
  62.   可以参考下面的代码看:
  63.   下面的运行结果符合我们期望,因为 变量a、b、c 分别对应堆栈  60(%esp) 56(%esp) 52(%esp)
  64.   这样计算结果不会互相干扰。得到的结果就是 6+5-4 == 7

  65.   1     .file   "mm.c"
  66.   2     .section    .rodata
  67.   3     .align 4
  68.   4 .LC0:
  69.   5     .string "a is :%d,b is :%d, c is:%d, d is %d\n"
  70.   6     .text
  71.   7 .globl main
  72.   8     .type   main, @function
  73.   9 main:
  74. 10     pushl   %ebp
  75. 11     movl    %esp, %ebp
  76. 12     andl    $-16, %esp
  77. 13     subl    $64, %esp
  78. 14     movl    $5, 60(%esp)
  79. 15     addl    $1, 60(%esp)
  80. 16     movl    60(%esp), %eax
  81. 17     movl    %eax, 56(%esp)
  82. 18     subl    $1, 60(%esp)
  83. 19     movl    60(%esp), %eax
  84. 20     movl    %eax, 52(%esp)
  85. 21     subl    $1, 60(%esp)
  86. 22     movl    60(%esp), %eax
  87. 23     movl    %eax, 48(%esp)
  88. 24     movl    52(%esp), %eax
  89. 25     movl    56(%esp), %edx
  90. 26     leal    (%edx,%eax), %eax
  91. 27     subl    48(%esp), %eax
  92. 28     movl    %eax, 44(%esp)
  93. 29     movl    $.LC0, %eax
  94. 30     movl    44(%esp), %edx
  95. 31     movl    %edx, 16(%esp)
  96. 32     movl    48(%esp), %edx
  97. 33     movl    %edx, 12(%esp)
  98. 34     movl    52(%esp), %edx
  99. 35     movl    %edx, 8(%esp)
  100. 36     movl    56(%esp), %edx
  101. 37     movl    %edx, 4(%esp)
  102. 38     movl    %eax, (%esp)
  103. 39     call    printf


  104.   1 #include <stdio.h>
  105.   2
  106.   3 int main ()
  107.   4 {
  108.   5
  109.   6     int j,i = 5;
  110.   7     int a = ++i;
  111.   8     int b = --i;
  112.   9     int c = --i;
  113. 10     int d = a + b - c;
  114. 11     printf("a is :%d,b is :%d, c is:%d, d is %d\n", a, b, c, d );
  115. 12     //j = (++i)+(--i)-(--i);
  116. 13     //printf("j is :%d,i is :%d\n",j, i);
  117. 14     getchar();
  118. 15 }
复制代码

作者: dingning239    时间: 2011-03-22 16:21
回复  dingning239


你这问题真是对不起你的头像啊,还搞得很求是一样,自己错了就承认,不要再这么折 ...
churchmice 发表于 2011-03-22 15:30



    拜托,废话别在这里说!!!!!
作者: dingning239    时间: 2011-03-22 16:28
回复 45# hebingyue


    多谢你的指点,这样的分析是我要的结果,不像其他说空话、废话的人!
作者: cjaizss    时间: 2011-03-22 16:29
拜托,废话别在这里说!!!!!
dingning239 发表于 2011-03-22 16:21



    为了一个不同编译器解释不一样的行为去深究,你觉得有必要吗?什么叫未定义行为,也就是如果你运行这个导致硬盘废掉,也丝毫不违背C语言标准的规定.
   真要想知道为什么会这样,那么你把你编译链接出来的执行程序反编译一下看看不就行了
作者: dingning239    时间: 2011-03-22 16:33
楼上的,你说的对我来说没有一点用,这个帖子到此结贴!

感谢pmerofc hebingyue  egmkang 三位的回答!
作者: cjaizss    时间: 2011-03-22 16:38
楼上的,你说的对我来说没有一点用,这个帖子到此结贴!

感谢pmerofc hebingyue  egmkang 三位的回答!
dingning239 发表于 2011-03-22 16:33



    没有一点用?
   "你把你编译链接出来的执行程序反编译一下看看不就行了"
  这几个字看清楚了吗?
作者: dingning239    时间: 2011-03-22 16:42
拜托,本帖已结贴,请不要再针对这个问题扯淡。而且你说的这些前几楼的朋友已经办到,所以属于xxx。
作者: cjaizss    时间: 2011-03-22 16:45
拜托,本帖已结贴,请不要再针对这个问题扯淡。而且你说的这些前几楼的朋友已经办到,所以属于xxx。
dingning239 发表于 2011-03-22 16:42



    真是晕死,一开始是你在这里问一个绝对无聊的问题,别人给了你建议你又不采纳。
  我无法解释是因为我很有可能编译器编译出来的结果跟你的编译器不一样,也就是你可能得到这个结果,而我得到另外一个,那我又如何解释呢?
作者: dingning239    时间: 2011-03-22 16:49
建议你看看 hebingyue  的求解过程,这是我需要的结果,我需要的是一个计算方法,而不是什么未标准定义之类的言辞,请不要再纠缠这个问题,谢谢!
作者: cjaizss    时间: 2011-03-22 16:51
本帖最后由 cjaizss 于 2011-03-22 16:58 编辑
建议你看看 hebingyue  的求解过程,这是我需要的结果,我需要的是一个计算方法,而不是什么未标准定义之类 ...
dingning239 发表于 2011-03-22 16:49



    。。你还真没看懂我的话。我不是说了嘛,很有可能我的编译器和你的编译器的结果不一样,而正巧他的编译器行为和你的一样。
  既然你自己想知道,自己objdump -D看看你的程序不就得到了跟他一样的结果吗?
作者: cjaizss    时间: 2011-03-22 17:02
拜托,废话别在这里说!!!!!
dingning239 发表于 2011-03-22 16:21



    问问题还问的不耐烦了,人家给了善意的建议,还发火,什么人啊,这是
作者: maliya110    时间: 2011-03-22 17:37
{:2_175:} 对呀,问题解决了就OK,进行下一个话题试试...
作者: maliya111    时间: 2011-03-22 17:59
{:3_198:} 问题不是解决了吗?怎么还有断续...
作者: jhinux    时间: 2011-03-22 18:41
路过看看
作者: Oo狂且oO    时间: 2011-03-22 21:05
{:3_184:}在《C陷阱与缺陷》里面,作者不建议这么写!!!难以理解,不方便!!何苦呢??
作者: maliya112    时间: 2011-03-23 08:26
{:3_191:} 自加加与自减减还是OK。不算太难的,有空要好好看才行...
作者: gcjlx    时间: 2011-03-23 14:06
这个问题是未定义的,我运行的结果j=6.硬件平台为ARM11。
作者: jayklx    时间: 2011-03-23 14:54
建议你看看 hebingyue  的求解过程,这是我需要的结果,我需要的是一个计算方法,而不是什么未标准定义之类 ...
dingning239 发表于 2011-03-22 16:49



    可笑啊。。。一个没答案的题目居然做出来了。。。。
作者: dingning239    时间: 2011-03-23 16:39
回复 62# jayklx


    请到一边去笑,说风凉话没意思
作者: lkk2003rty    时间: 2011-03-24 12:23
回复 55# cjaizss


    淡定  淡定 为了这样一个无聊的问题不值当 生气
   其次  楼主也太懒了点 问问题之前先google下嘛 是在不行 自己动手像cjaizss说的反汇编 不懂了再问
作者: dragoxiao    时间: 2011-03-24 17:03
貌似“ (++i)+(--i)-(--i)”这个表达式的求值顺序是没有定义的吧?这样的话,在不同编译环境下j的值可能会不一样的。
PS:i=4是一定的吧
作者: shadowlaser    时间: 2011-03-24 17:39
编译器对表达式是从右边开始读取的,所以结果可能是
j=6,i=4
作者: zengit    时间: 2011-03-24 22:54
交流一下,这是我的看法
pmerofc 发表于 2011-03-21 17:49



    这个链接很好,直接给出嘛,没必要闪闪躲躲
作者: pmerofc    时间: 2011-03-25 10:03
提示: 作者被禁止或删除 内容自动屏蔽
作者: jason680    时间: 2011-03-25 11:27
#include
#include

main ()
{   
     
   int j,i = 5;
    j = (++i)+(--i)-(--i);
    prin ...
dingning239 发表于 2011-03-21 11:18


XX问的XX问题,要XX答案......

XX都说了"不要通过运行来看结果"....

XX答案在这.....

不通过运行...
     int j,i = 5;
    j = (++i)+(--i)-(--i);

"不通过运行"...当然就不会有"运行"做用

得到答案就是 J = 5 + 5 - 5 = 5

XX答案就都是5

XX知道了吗?

(注:XX就是XX,别问XX是什么)

别跟我说complier怎样又怎样,那不符XX"不通过运行"题意....
作者: madoldman    时间: 2011-03-25 11:31
回复 65# dragoxiao


    i=4也不是一定的,发生了未定义行为,一切都是未定义的。
作者: wgzch    时间: 2011-03-27 15:45
这种代码没有可读性,完全没有这样写的必要,代码确实没有错,这些题都是一些学校里耍学生出的题~
作者: wwwcctvcomji    时间: 2011-03-28 18:39
这个跟java的优点像啊,我就只学了java。。。。
作者: jibcy    时间: 2011-03-28 23:12
6 +4 - 4
j = 6
i = 4
LZ是这样吗?
作者: lusir    时间: 2011-03-29 22:59
本帖最后由 lusir 于 2011-03-29 23:01 编辑

j=4,i=4;
++i=6;
--i=5;
--i=4;
j=i+i-i=4+4-4=4
作者: LinuxSurfing    时间: 2011-03-30 19:01
i = 4 j = 11 没运行也不知道对不对




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2