| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 770 人关注过本帖
标题:这几天论坛提的问题
只看楼主 加入收藏
小鱼儿c
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:14
帖 子:852
专家分:1317
注 册:2011-4-1
结帖率:95.74%
收藏
 问题点数:0 回复次数:10 
这几天论坛提的问题
求答案及解释,++--问题
#include<stdio.h>
#include<string.h>
int main()
{
    int a=4;
    printf("%d %d %d %d\n",++a,--a,a++,a--);
    return 0;
}
原帖:https://bbs.bccn.net/thread-360602-1-1.html

下面解答:
复制来自:http://

在这里我使用了编译的结果是:8,8,7,8
用TC2.0编译的结果是:8,7,7,8
VC6.0我没有安装,所以没有试过,也没办法分析。
这里我们可以看到,由不同的编译器产生了不同结果,可见这个问题是依赖编译器的理解和实现的。换句话说,对于i++和++i的处理本来就是非常具有歧义的,当然在自己应用中我相信也不会有任何程序员写出这样歧义的代码。但是作为一个问题,我们有必要分析一下不同编译器究竟如何理解i++和++i操作符的。
      我们在学习C的时候,应该已经大概知道了i++和++i两者的区别,即“++”符号在i之前还是之后,决定了i自增操作和他的语句的执行顺序的关系。即i++,理解为i在其语句中取原始值,++i在其语句中取自增后的新值。这一点是毫无疑义的。但是问题在于,网友的问题中又涉及到了i++,++i在作为参数时候的处理,所以这时候我们就会感到困惑,i++和++i在作为参数的时候,和进入堆栈的顺序之间有何关系呢?根据前面的实验,可见TC2.0和的处理不同,可见两者对其处理不同,那么造成这种不同的结果的原因是什么呢?我们从代码上无法看到差异,因此我们必须看汇编语言才能知晓,编译器到底把我们的代码翻译成了什么墨阳。下面我采用IDA反汇编编译器把生成的.exe文件:由于程序很小,所以我们很容易找到相应的汇编代码(TC2.0的程序中有很多中断的相关代码,更加难以找到),结果如下:
2005的代码
可见,++i和--i执行的时候直接改变了i的值,而i++和i--必须在所在的这个语句执行后才能改变i的值,所以i++作为参数时,实际上是这样的过程,
       printf("%d",i++);
相当于下面的语句:
       int temp=i;
       i=(i+1);
       printf("%d",temp);
因此上面的代码可以翻译为:
      int i=8;
      printf("%d,%d,%d,%d",++i,--i,i++,i--);
因此可以翻译为下面的等效代码:
i=8;
temp0=i; //temp0=8;
i--;     //7
temp1=i; //temp1=7
i++;     //8
--i;     //7
++i;     //i=8
printf("%d,%d,%d,%d",i,i,temp1,temp0);   
所以打印结果是8,8,7,8
---------------------------------------------------------------------------------------------------------
我们再看在TC2.0下的反汇编代码:
TC2.0下面的反汇编代码
可见,上面的行为可以翻译为下面的等效代码(TC2.0):
i=8;
temp0=i;        //这时8已经入栈,实际上通过ax寄存器直接压栈里了~~~,不存在temp0)
i--;                //i=7
temp1=i;        //这时7已经入栈,实际上通过ax寄存器直接压栈里了~~~,不存在temp1)
i++;               //i=8
--i;                 //i=7      
temp2=i;        //7已经入栈
++i;               //i=8
temp3=i;        //8已经入栈
printf("%d,%d,%d,%d",temp3,temp2,temp1,temp0);
输出结果是:8,7,7,8
----------------------------------------------------------------------------------------------------------------------
下面我们将总结和分析两种编译器的处理之间有何不同:@@@@@@
请注意两者的区别主要是,他们是一边处理自增自减并一边随时入栈,还是先处理完所有自增自减之后再最后统一一次性的入栈。
 
----------------------------------------------------------
【补充】:在这里这样总结他们的区别是不完善的,实际上涉及到(1)缓存 i 的值,(2)++/--运算符的执行,(3)push i 或 缓存值。
 这三者之间的顺序问题。以上三者之间的顺序的微小差别都能对结果产生关键影响。请参考本文最后的补充。
    --hoodlum1980 @ 2011年10月12日
----------------------------------------------------------

(1)在TC下面属于前者,每执行一个语句,就把i通过ax寄存器马上入栈了,所以参数入栈和i++等语句是交叉交替性进行的。这里的i++和++i的主要区别在于压栈是在i自增之前还是之后。
i++相当于:先入栈,再自增。
++i相当于,先自增,再入栈。
所以我们看到下面的参数:从右到左:
i--: 入栈8,i=7
i++:入栈7,i=8
--i:i=7,入栈7
++i:i=8,入栈8
所以导致栈里面的参数是8,7,7,8,所以打印结果是8,7,7,8.
(2)在上面的中属于后者,是先为i++和i--保存值,然后执行完所有的自增和自减,最后一次性的把所有参数入栈。在这里i++和++i的区别
主要是是否把i的值保存到另一个位置:而且最大不同点在于这里不马上入栈,而是等所有参数处理后统一入栈。
i++:先缓存i的原始值,然后i自增。最后入栈时,用i的原始值入栈。
++i:i自增,不缓存i的原始值。最后入栈时,是更新后的i。
所以我们看到在中的顺序是:
i--: 缓存8,i=7
i++:缓存7,i=8
--i:i=7
++i:i=8
参数一次性依次入栈:第一个缓存值8,第二个缓存值7,i的当前值8,i的当前值8。
所以这时候栈的数据是:8,8,7,8.(从左到右)。
所以打印结果是:8,8,7,8.

------------------------------------------------------------
【补充】对 VC6.0 的分析(如提问者所述:结果是 8,7,8,8)
           --hoodlum1980 @ 2011-10-12
------------------------------------------------------------
 
    现在补充下对 VC6.0 的debug版本的分析。本题目本质上是分析编译器如何处理入栈和++等操作符之间的关系。也就是说结果取决于编译器如何将参数push到栈中。VC6.0 的结果打印出来是 8,7,8,8。其汇编代码如下:
.text:00401028                 mov     [ebp+var_4], 8  ; int i = 8;
.text:0040102F                 mov     eax, [ebp+var_4]
.text:00401032                 mov     [ebp+var_8], eax ; int tmp1 = i;
.text:00401035                 mov     ecx, [ebp+var_8]
.text:00401038                 push    ecx             ; push tmp1; (8)
.text:00401039                 mov     edx, [ebp+var_4] ; int tmp2 = i;
.text:0040103C                 mov     [ebp+var_C], edx
.text:0040103F                 mov     eax, [ebp+var_C]
.text:00401042                 push    eax             ; push tmp2; (8)
.text:00401043                 mov     ecx, [ebp+var_4]
.text:00401046                 sub     ecx, 1
.text:00401049                 mov     [ebp+var_4], ecx ; --i; (之后i = 7)
.text:0040104C                 mov     edx, [ebp+var_4]
.text:0040104F                 push    edx             ; push i; (7)
.text:00401050                 mov     eax, [ebp+var_4]
.text:00401053                 add     eax, 1
.text:00401056                 mov     [ebp+var_4], eax ; ++i; (之后i=8)
.text:00401059                 mov     ecx, [ebp+var_4]
.text:0040105C                 push    ecx             ; push i; (8)
.text:0040105D                 push    offset ??_C@_0N@KFBM@?$CFd?0?$CFd?0?$CFd?0?$CFd?6?$AA@ ; "%d,%d,%d,%d\n"
.text:00401062                 mov     edx, [ebp+var_4]
.text:00401065                 add     edx, 1
.text:00401068                 mov     [ebp+var_4], edx ; i++; (之后i=9)
.text:0040106B                 mov     eax, [ebp+var_4]
.text:0040106E                 sub     eax, 1
.text:00401071                 mov     [ebp+var_4], eax ; i--; (之后i=8)
.text:00401074                 call    printf
.text:00401079                 add     esp, 14h
复制代码

    
    我们翻译上面的汇编代码的等效代码如下:
 
int i = 8;
int tmp1 = i;
int tmp2 = i;  //临时变量 tmp1 和 tmp2 是实际上存在!
--i;
int tmp3 = i;  //临时变量 tmp3 和 tmp4 是实际上不存在。本质是push i。
++i;
int tmp4 = i;

i++;  //此处是处理语句中的两个后置操作符。
i--;

printf("%d,%d,%d,%d\n", tmp4, tmp3, tmp2, tmp1);
复制代码

    这里我们注意到,VC6 本质上也是一边入栈一边处理前置运算符。VC6是先处理两个前置的运算符(++i和--i),并在此过程中就入栈参数,当参数入栈完毕后最后处理两个后置运算符(i++和i--)。同时 VC6 和 Vs2005的处理过程非常类似,但是不同在于处理顺序不同。VC6先处理前置运算符(--i 和 ++i),然后最后处理后置运算符(i++,i--),注意这个顺序是依照了参数入栈顺序(从右到左)。而VS2005和VC6的处理顺序相反。
 

     【总结】
 
    尽管我们分析了上面的汇编代码,但是实际上还是有些云里雾里。不同编译器产生不同的结果的本质原因在于:在处理++,--运算符和入栈之间的顺序关系,同时还需要了解的是,前置的运算符一般在执行本语句之前就执行,因此无需缓存值。而后置运算符通常的处理则通常需要缓存值。由于本问题中是对同一个变量多次使用++,--运算符,且对其入栈,因此运算符和入栈之间的顺序对结果有着关键影响。通过下表可以进行直观的对比:
 
int i = 8;
printf ( "%d,%d,%d,%d\n", ++i, --i, i++, i-- );
 
VC6.0
VS2005
TC2.0
tmp1 = i
push tmp1
tmp2 = i
push tmp2
--i
push i
++i
push i
i++
i--
 
 
tmp1 = i
i—
tmp2 = i
i++
--i
++i
push tmp1
push tmp2
push i
push i
tmp1 = i
i—
push tmp1
tmp2 = i
i++
push tmp2
--i
push i
++i
push i
8,7,8,8
8,8,7,8
8,7,7,8
 
    备注:上面的 tmp1,tmp2 在 VC6和 VS2005中是栈上的实际临时变量(它们是由于两个后置运算符而产生的),在TC2.0中是使用AX寄存器中转。
 
    仔细观察上面的表格中可以发现,push 了 4 个 i 的顺序是没有疑问的,由于有后置运算符,所以需要两个临时变量来缓存当前值。结果不同的原因在于,不同编译器,(1)缓存 i 的当前值,(2)处理 ++,--运算符 和 (3)push 语句之间的顺序不同,因此导致结果不同。
 
PS : 就算你明白你得不到什么。我想我们也不会写那样的代码,也不会出那样的题目。没有什么意义。。。

c 要怎么学习。 学好了c 我们能做什么?
我来谈谈自己一点小小的想法。

开始我们不要认为语言哪个好哪个差,这个没必要讨论。完全浪费时间。
高手都说语言是工具。 既然是工具何必要选择呢。只要需要 适合就可以了。
学好了一门,学习他的思想 学习他的模式。通过它来了解计算机。其他的工具自然会用了。
就像我们会QQ聊天工具,难道别的聊天工具我们还要学习怎么用他们。(除非编程者故意写的表态差不多)。。

C这门语言作为自己第一门语言 我觉得再好不过语言,
低一点看 可以考级,基本什么考试 c都是主要 我是说一般。。
长一点: 既可以了解底层 也可以有助于学习面向对象的语言 起码学习c++的时候非常方便了 自己感受。。

每个语言都有自己的优势,一个语言要能做什么,要看你自己的能力吧。你能力只能写垃圾 那他就只能写出垃圾。

c语言需要上培训吗?

你有钱的话 觉得钱对你完全没有概念的话。
上上也好 有老师好一点吧。

不管什么语言都是要多写 多看 多想 坚持 、
但要做到是多么难啊。

这几天写代码 写的蛋疼啊、

希望大家都都一起进步。。。。

完全是自己的一点想法而已、、说说而已 说的不对请指正。
但本人不会回
搜索更多相关主题的帖子: include 安装 return 编译器 
2012-02-10 16:43
weipeng1217
Rank: 5Rank: 5
等 级:职业侠客
帖 子:175
专家分:386
注 册:2012-1-12
收藏
得分:0 
版主辛苦了、、

C坛友交流群 群号:161091913 ,欢迎经常在线的朋友加入,一起学习,一起进步。。
2012-02-10 16:52
hnuhsg1226
Rank: 9Rank: 9Rank: 9
来 自:中国
等 级:蜘蛛侠
威 望:2
帖 子:314
专家分:1314
注 册:2011-3-27
收藏
得分:0 
呵呵,辛苦了

我的地盘
2012-02-10 16:55
有容就大
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:东土大唐
等 级:版主
威 望:74
帖 子:9048
专家分:14309
注 册:2011-11-11
收藏
得分:0 
.

梅尚程荀
马谭杨奚







                                                       
2012-02-10 16:58
fenghelong
Rank: 3Rank: 3
来 自:上海
等 级:论坛游侠
威 望:2
帖 子:209
专家分:197
注 册:2011-8-18
收藏
得分:0 
ds
2012-02-10 19:03
小赵q1
Rank: 8Rank: 8
等 级:蝙蝠侠
威 望:4
帖 子:492
专家分:777
注 册:2011-8-26
收藏
得分:0 
顶个
2012-02-10 19:05
ljl123970
Rank: 2
等 级:论坛游民
帖 子:31
专家分:42
注 册:2012-1-30
收藏
得分:0 
楼主的 感想发的实在,至少帮我指引了方向。不用那么纠结于学C好不好
 贵在坚持
2012-02-10 21:24
吴小君
Rank: 3Rank: 3
等 级:论坛游侠
帖 子:102
专家分:198
注 册:2012-1-2
收藏
得分:0 
呵呵,我顶起来

小弟学习C语言刚入门,请大侠们多多指教,不吝赐解!
2012-02-10 21:42
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
收藏
得分:0 
这个帖子写得辛苦,看的也辛苦。

顶顶吧。
2012-02-10 22:53
zxd675816777
Rank: 7Rank: 7Rank: 7
等 级:黑侠
帖 子:252
专家分:631
注 册:2012-2-3
收藏
得分:0 
版主辛苦了啊

数学好难!
2012-02-11 02:49
快速回复:这几天论坛提的问题
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.014792 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved