我在torboc 在运行该等式是交换a,b值,但不知道为什会这样。请高手指点下。该等式是怎样一步一步运行。在turboc 此等式一步就运行玩。分开运行就会是不同的结果

解决方案 »

  1.   

    ildasm可以查看其类似汇编代码的IL
      

  2.   

    a=b+(b=a)*0
    是a和b的交换吗,先进的东西
    我交换赋值时都使用个临时变量
      

  3.   

    a=b+(b=a)*0是如何编译?
    解:
    1)b=a;
    2)b*0
    3)b+0
    4)a=b+0
    5)a=bSo: a=b=a,并没有交换,原来的b不见了。
      

  4.   

    int a=13;
    int b=31;
    a = b + (b = a) * 0;中间语言为:  IL_0001:  ldc.i4.s   13
      IL_0003:  stloc.0
      IL_0004:  ldc.i4.s   31
      IL_0006:  stloc.1
      IL_0007:  ldloc.1
      IL_0008:  ldloc.0
      IL_0009:  stloc.1
      IL_000a:  stloc.0编译结果实际上就是交换a,b的值,什么乘法,加法都没做。PS:ldloc -> load local variable onto the stack
        stloc -> pop value from stack to local variable
      

  5.   

    int a=13; 
    int b=31; 
    a = b + (b = a) * 0; 中间语言为:   IL_0001:  ldc.i4.s   13 
      IL_0003:  stloc.0 
      IL_0004:  ldc.i4.s   31 
      IL_0006:  stloc.1 
      IL_0007:  ldloc.1 
      IL_0008:  ldloc.0 
      IL_0009:  stloc.1 
      IL_000a:  stloc.0 编译结果实际上就是交换a,b的值,什么乘法,加法都没做。 
    -------------------------------------------------------------
    为什么是这样啊?
      

  6.   

    a ^= b;
    b ^= a;
    a ^= b;
      

  7.   

    a=b+(b=a)*0a=b  ---此处已做了赋值么?
    +(b=a)*0   ----此处呢?
      

  8.   

    发个C#反汇编的 int a=13;  
    00000000  push        ebp  
    00000001  mov         ebp,esp 
    00000003  sub         esp,0Ch 
    00000006  push        edi  
    00000007  push        esi  
    00000008  push        ebx  
    00000009  mov         dword ptr [ebp-4],ecx 
    0000000c  xor         edi,edi 
    0000000e  xor         esi,esi 
    00000010  mov         edi,0Dh 
    int b=31;  
    00000015  mov         esi,1Fh 
    a = b + (b = a) * 0; //*0被优化掉了
    0000001a  mov         ebx,esi 
    0000001c  mov         esi,edi 
    0000001e  mov         edi,ebx 
      

  9.   

    c#的编译器可以这么写 vc的可不能 vc是从右到左的读
      

  10.   


    a=b+(b=a)*0 
    现运算 (b=a)
    然后运算 (b=a)*0
    最后运算
    a=b+(b=a)*0 
      

  11.   

    a=b+(b=a)*0
    等同于
    b=a;
    a=b+a*0;
      

  12.   

    24楼的此贴是我发的。
    你连这表达式都没看懂,还谈什么这样运算,如果像你这样想的话早就结贴了。
    18楼的你写的汇编能不能做些解释啊,哪里能看懂。
    int a=13;   
    00000000  push        ebp   
    00000001  mov         ebp,esp  
    00000003  sub         esp,0Ch  
    00000006  push        edi   
    00000007  push        esi   
    00000008  push        ebx   
    00000009  mov         dword ptr [ebp-4],ecx  
    0000000c  xor         edi,edi  
    0000000e  xor         esi,esi  
    00000010  mov         edi,0Dh  
    int b=31;   
    00000015  mov         esi,1Fh  
    a = b + (b = a) * 0; //*0被优化掉了 
    0000001a  mov         ebx,esi  
    0000001c  mov         esi,edi  
    0000001e  mov         edi,ebx
      

  13.   

    int a=13;    
    00000000  push        ebp    
    00000001  mov         ebp,esp   
    00000003  sub         esp,0Ch   
    00000006  push        edi    
    00000007  push        esi    
    00000008  push        ebx    
    00000009  mov         dword ptr [ebp-4],ecx   
    0000000c  xor         edi,edi   
    0000000e  xor         esi,esi//这里以前是函数准备工作   
    00000010  mov         edi,0Dh//a=13;   
    int b=31;    
    00000015  mov         esi,1Fh  //b=31
    a = b + (b = a) * 0; //*0被优化掉了 //一下语句是这句话的由vs.net 调试得出反汇编 
    0000001a  mov         ebx,esi  b(esi) 赋予 ebx 
    0000001c  mov         esi,edi   a(edi) 赋予 b(esi);
    0000001e  mov         edi,ebx  临时变量 ebx 赋予 a(edi)
     根本没有*0的计算因为vs.net 会更具x+0 = x 直接优化
      

  14.   

    运算符优先顺序,对比一下a=(b=a)*0+b
      

  15.   

    劝lz不用去研究了,这种写法和软件工程格格不入的
    如果有公司出这种题目,你可以一笑了之。microsoft,ibm,intel这种公司从来不出这种题目的。 
    还有象什么goto语句在这个语言中有没有,我看到这种题目,掉头就走
      

  16.   

    看来c#和c/cpp类似的地方也不一样阿
      

  17.   

    lz说turboc运行交换不对吧。
    当做c程序运行是不交换的,c#程序就交换了。
      

  18.   

    对于a=(b=a)*0+b这个式子,本没什么好说的,按逻辑上来说肯定a跟b没有实现交换啦..
    但是用C#试了一下,结果大吃一惊,交换了.奇怪,又用C++试了一下,没有交换..
    毕竟对错不能按编译器说的算吧,逻辑上应该没交换就是没交换,你交换了,不管你是谁都是错的....下面是C++写的(编译器VC6.0):下面是C#写的:
      

  19.   

    假设a=10;b=25;
    a=b+(b=a)*0;
    没有学过编译原理,不过我想应该是这样的
    1)b=a;这步其实在编译的时候应该是首先把b值用一个临时变量temp存起来了,然后再执行b=a,这个temp变量在整个a=b+(b=a)*0这个式子没有计算完之前是不会被销毁的。
    2)然后执行(b=a)*0结果为0;
    3)执行a=b+0,实质上是执行a=temp+0;
    我做了几个小测试来验证上面的观点:
    1)计算 a=b-(b=a)*0结果和上面式子效果一样
    2)计算a=b-(b=a)实质上就为:b=a返回为10,然后计算a=25-10=15,最终a=15,b=10;
      

  20.   

    毫无意义。不同的编译器结果不同,就算是C#,也许在VS2007里是另一种结果。
      

  21.   

    确实是实现a,b交换!
    执行步骤:
    按优先级编译:  原式:a=b+(b=a)*0 
    1)执行括号:b=a  => 结果为把a值赋给b(其实是初始化)
    2)执行乘法:×0 => 结果为0
    3)执行加法:b+0 => 结果为b
    4)执行等式:a=b => 结果为把b值赋给a,并输出 (此处其实先有变量初始化,然后赋值输出,也可以分开理解)
     
    ****注意:此处有两点要注意的地方,一个是变量的初始化,另一个是运算的优先级
    一、初始化:编译器会把"等号"右边的元素(变量)初始化,而把"等号"左边的元素(变量)保留元素(变量)符号
      假设,此处 int a=1;int b=2;
        那么在初始化这一步中有: a=2+(b=1)*0;二、运算的优先级…………大家应该都明白(在执行过程中也有说明了),不再赘述。 
      

  22.   

    a=10, b=20
    VS2008 C++ 的结果:a=10,b=10
    VS2008 C#  的结果:a=20,b=10
      

  23.   

    理论上, 这个得看编译器怎么编译的, 不一定是交换两个元素的值!
    最好的方法
    a=a^b;
    b=a^b;
    a=a^b;
      

  24.   

    奇妙- -||#include "stdio.h"
    main(){
    int a=1,b=5;
    a=b+(b=a)*0;
    printf("%d,%d",a,b);
    getch();
    }这段代码可以交换值,且在表达式的加法运算中b等于原值
    而换成了a=b+(b=a)*5;之后(乘任意一个不为零的数)b又变成了a
      

  25.   

    在楼主的编译器中,确实是实现a,b交换!
    原因是在于
    表达式的解释顺序
    在楼主的编译器中
    a=b+(b=a)*0
    假译int a=11;int b=22;
    则a=b+(b=a)*0的
    解释顺序是
    b  //b=22 将值22调入累加器
    (b=a)          //b=11 a=11 
    (b=a)*0        //b=11 a=11 
    b+(b=a)*0      //b=11 a=11 这里是将累加器中的值22与(b=a)*0的值相加,当然表达式的值就是22了 
    最后a=b+(b=a)*0  结果就是a=22 b=11了,实现了交换最后还是劝楼主不要这么写
    除非确定使用的编译器的解释顺序
    因为不同的编译器对解释顺序做了一定的优化,
    解释顺序顺序不一定相同
    结果会因为编译器的不同有所不同
      

  26.   

    a=b+(b=a)*0 对于C++来说,如果编译器没有优化错误,就应该是a,b都等于a的初始值。没有任何规定说如果一个乘数是0,则乘式可以不计算,所以b=a一定会先于b+(b=a)*0计算,最终必然导致b+(b=a)*0变为b的当前值,也就是a的初始值楼上的假设说的很好,“楼主的编译器确实是这个结果”,注意,这种结果不是本该如此的结果,而是应该看作是一个错误。至于C#个人觉得没有理由它能交换,如果可以,也该认为是编译器的一个误解。巧技害人,我觉得中国学生现在有个严重的误区,觉得研究一些非常“巧妙”的技巧对学习有帮助。但是在现代软件工程中,这种东西绝大多数情况对工程都是有害的。
      

  27.   

    http://topic.csdn.net/t/20060724/02/4899577.html看Ivony的回复
      

  28.   

    c#不太懂,但是语言是都差不多的.解析顺序原则:(按考虑顺序排)
      1.calculate from left to right
      2.priority
      3.associativity
    所以:(假设 a = 10, b = 15)
    a = b + (b = a) * 0;
      1. a = 15 + (b = a) * 0;
      2. a = 15 + (b = 10) * 0;
      3. a = 15 + 10 * 0;  (b 已经是10了)
      4. a = 15 + 0;
      5. a = 15;
      

  29.   

    这种问题结贴掉算了,不用再讨论了.讨论这个句子的写法不过就是在讨论回字的四种写法,我也知道一种不用临时变量就可以交换的方法.a = 13; b= 31;
    a = a + b;
    b = a - b;
    a = a - b;可是有意思么,写出来的结果就是让别人给你维护的时候不知道你想干嘛.楼上有位兄弟说得好,如果哪个公司出这样的题目给我做,调头就走.
      

  30.   

    我没有学过汇编,在学C语言的时候就怀疑过语句在执行过程中的细节问题,(我们老师是用DELPHI的,所以我也没有学好C),今天看了这个帖子终于知道了计算机语言的真一些实执行过程了。
      

  31.   

    多写几年程序,以后有一天你会发现这些所谓的技巧是害人的,就像 int i = 4["ABCDE"] + 3["ASDF"];或者 
    int a = 3;
    int i =  a++ * a++ ;这样的技巧一样, 毫无意义.
      

  32.   

    我只想说: 
    在c语言或者C++ 中  b=a  的结果不是, a, 也不是 b.  结果是 true  (在c中是 1 )比如 b==a 的结果是 如果b等于a,则真,反之则假.所以如果你在程序中把 if( b==a ) 写成 if( b=a ) 的话, 那么后者将永远为真, 因为赋值总是为真.a=b+(b=a)*0也就是 a = b+1*0 (编译器优化会自动直接把b=a翻译成1, 甚至直接翻译成: a=b) 我是说的我懂得C,c++ 不知道c#里面怎么样的.
      

  33.   

    //-------------
    所以如果你在程序中把 if( b==a ) 写成 if( b=a ) 的话, 那么后者将永远为真, 因为赋值总是为真. 
    //-------------
    如果a=0,还为真吗?
      

  34.   

    pengdean 
     
    等 级:
     发表于:2007-09-29 19:11:0327楼 得分:0 
    24楼的此贴是我发的。 
    你连这表达式都没看懂,还谈什么这样运算,如果像你这样想的话早就结贴了。 
    18楼的你写的汇编能不能做些解释啊,哪里能看懂。 
    int a=13;    
    00000000  push        ebp    
    00000001  mov         ebp,esp   
    00000003  sub         esp,0Ch   
    00000006  push        edi    
    00000007  push        esi    
    00000008  push        ebx    
    00000009  mov         dword ptr [ebp-4],ecx   
    0000000c  xor         edi,edi   
    0000000e  xor         esi,esi   
    00000010  mov         edi,0Dh   
    int b=31;    
    00000015  mov         esi,1Fh   
    a = b + (b = a) * 0; //*0被优化掉了  
    0000001a  mov         ebx,esi   
    0000001c  mov         esi,edi   
    0000001e  mov         edi,ebx 
     无语  井底之蛙  
    真不知道你能懂什么
      

  35.   

    a=b+(b=a)*0 b 是表达式 计算的时候跑出它的值 储存在没有名字的临时变量里先算(b=a)*0 结果 b=a;所以就是 a=临时变量 +0这样基于编器的算法可移植性很差
      

  36.   

    ps:a=b+(b=a)*0+b;
    计算为b是原B值
    b是赋值a后的值
      

  37.   

    多么搞笑的楼主从哪里抄这么个式子来引得大家在下面瞎猜。这个表达式我没记错的话,是俺半年前写在CSDN上的,那个时候就详细的分析了C#对它的处理,楼主或其他摘抄者敬业点就不会让大家在下面瞎猜。在这个式子上,C#是有确定性的结果的,具体的条文请默诵C#规范。
    正确的解法是:
    a = b + ( b = a ) * 0首先编译器根据运算符优先级,先找到这个里面最优先的运算符*,确定结合顺序如下:
    a = ( b + ( ( b = a ) * 0 ) )接下来,根据C#规范,会从左至右计算每个子表达式的值,第一个子表达式b,值为当前b值,记为b',第二个子表达式b = a,值为当前a值,记为a',最后一个表达式0,值为0。接下来,根据刚才确定的顺序,依次进行计算。
    b = a已经运算完毕,值为a',这时进行乘法运算,然后进行加法运算,然而C#的编译器意识到这个加法是没有意义的,故而优化掉,所以,整个表达式被优化为:
    a = b'加上刚才计算子表达式的值时计算的b = a。故而C#的编译器做出了最简的IL代码。
      

  38.   

    这并不是什么技巧而是C#的BUG,这样编译不符合C#自己所定的语义
      

  39.   

    同一个标识符却在同表达式中出现了两个值不是bug是什么呢,以C#的语法语义演算的结果和实际不符。
      

  40.   

    在c语言或者C++ 中  b=a  的结果不是, a, 也不是 b.  结果是 true  (在c中是 1 )比如 b==a 的结果是 如果b等于a,则真,反之则假.所以如果你在程序中把 if( b==a ) 写成 if( b=a ) 的话, 那么后者将永远为真, 因为赋值总是为真.a=b+(b=a)*0也就是 a = b+1*0 (编译器优化会自动直接把b=a翻译成1, 甚至直接翻译成: a=b) 我是说的我懂得C,c++ 不知道c#里面怎么样的
    --------------------------------------------
    就这还懂C++,概念一塌糊涂。不要说在a=b+(b=a)*0里编译器不可能什么把b=a“优化”成1,就是在if(b=a)中也不
    可能,否则就不是C++或C编译器了而成二百五编译器了。在C++和C中只要是非0值转换为逻辑值都是真,并不需要
    为1.
      

  41.   

    编译器编译和优化的方式都有不同,感觉c#编译器应该是按自下而上的方式来编译这条语句,所以a=b 跟b=a 处在树深相同的地方。
      

  42.   

    試了下
    C#中的結果
    a=20
    b=10
    VB.NET中的結果
    a=20
    b=20
    C++中的結果
    a=10
    b=10
    看來有很大的出入,不知道在其它語言上會有什麼變化
    如保編譯器有關,那麼C#和VB.Net為什麼也會不同呢
      

  43.   

    class Program
    {
    static void Main(string[] args)
    {
    int a = 32;
    int b = 16;
    a = b + (b = a) * 0;
    Console.WriteLine("a="+a+"  b="+b);
    Console.ReadKey();
    }
    }
    测试了还真是交换了值,真是强。,语言这东西太厉害了!
      

  44.   

    这个c#可以
    c++可以如下:
    a=a^b^(b=a);
    同样11字符完成交换.
      

  45.   

    同意10楼的观点
    a=b+(b=a)*0
    运行的结果是a的值没有改变,
    关于交换a,b的值,可以这样去想
    下面我们看另外一个东西。定义两个符号#和,这两个符号互为逆运算,也就是说(x # y) @ y = x。现在依次执行下面三条命令,结果是什么?
    x <- x # y
    y <- x @ y
    x <- x @ y
    执行了第一句后x变成了x # y。那么第二句实质就是y <- x # y @ y,由于#和@互为逆运算,那么此时的y变成了原来的x。第三句中x实际上被赋值为(x # y) @ x,如果#运算具有交换律,那么赋值后x就变成最初的y了。这三句话的结果是,x和y的位置互换了。
        加法和减法互为逆运算,并且加法满足交换律。把#换成+,把@换成-,我们可以写出一个不需要临时变量的swap过程
    a=a + b;
    b=a - b;
    a=a - b;
    在为运算中我们知道^是它本身的逆预算,所以我们可以得到这样一个诡异的swap程序
    a=a^b;
    b=a^b;
    a=a^b;
      

  46.   

    我来说说看这个帖子的收获:(本人是菜鸟,可能不对哦,嘿嘿!)    这个问题就是揭示出了计算机到底是怎么理解程序语言的,确切的的说,应该是编译器到底怎么去编译程序语句。
    对于 a=b+(b=a)*0 这个式子来说:
    因为C#是从左到右执行的,所以
    C#首先会从b的内存地址中读取b的值然后保存到某个地方,然后再去求(b=a)*0的值,再做这一步的时候,首先要求出(b=a)的值,
    这时C#会把a的值写到b的内存地址中,从这个时候起,b的值就发生变化了,求出(b=a)的值(为a的值)后,再*0得到(b=a)*0的值(为0),再去求b+(b=a)*0的值,也就是b+0的值,然而这个b的值并不是这个时候才从b的内存地址里去取,因为C#是从左到右编译的,取b的值的操作在刚开始的时候就已经执行了,它就是原来的b的值,所以b+0的值就是原来b的值,然后再把这个值赋给a,也就是写入a的内存地址里,这时a的值也就发生变化了,所以执行完这个表达式后就交换了a,b的值。
      

  47.   

    每个编译器都不大一样吧.
    C#是把这些变量看成值的,所以(b=a)不会把b覆盖;TC里把这些变量看成地址,直接就把a的值放到b对应的地址的内存上去了.
      

  48.   

    我倒,
    //------------
    每个编译器都不大一样吧. 
    C#是把这些变量看成值的,所以(b=a)不会把b覆盖;TC里把这些变量看成地址,直接就把a的值放到b对应的地址的内存上去了.
    //------------
    [(b=a)不会把b覆盖]:那它们还怎么交换值呢?你不会是说在表达式a=b+(b=a)*0执行完后才执行的(b=a)吧???
      

  49.   

    因为是栈运算,a=b+(b=a)*0,入栈时右边为b)ba=0(*+ 就是如下图的二叉树
      

  50.   

    看了楼上的帖,其实我只想知道的到底在b=a时,为什么左边b值也跟着变成a。但好像没变,不知道编译是怎么编译出来。听楼上的说c++编译又是其他结果,但我用turboc编译是交换两个值。我不提议大家这样编程,让人看不东此程序,只是要弄清下式子编译的原理。
      

  51.   


    当时汇编挂了 唉
    那段反汇编的代码没有看懂不过表达式的计算是在栈中进行处理的(好像是数据结构的内容)
    没有优化过的代码
    具体的执行过程有个如下:( a = 5 地址@0AX; b = 3 地址@0CX) 首先把中缀表达式转化为后缀表达式存入队列原来的中缀表达式               队列中的后缀表达式
    a=b+(b=a)*0     ---->      abba=0*+= 然后开始进行计算:
    (栈里的每个变量应该包含2个信息 一个是它的value 一个是它的地址site)
    首先将a压入栈 既压入 5 @0AX 
    压入b        既压入 3 @0CX
    压入b        既压入 3 @0CX
    压入a        既压入 5 @0AX 
    读取=
    弹出栈顶最上面的2个数值 进行赋值运算b=a  既 b的地址@0CX处变为5  a的地址@0AX处仍为5  返回的结果是b  既(5 @0CX) 不是临时变量 是b
    压入结果b    既 5 @0CX
    压入0          0 临时变量 地址未知
    读取*
    弹出栈顶最上面的2个数值 进行计算 b*0 既 5*0 返回的结果是0 临时变量
    压入结果0       0 临时变量 地址未知
    读取+
    弹出栈顶最上面的2个数值 进行计算 b+0 既 5+0 返回的结果是5 临时变量
    压入结果5       5 临时变量 地址未知
    读取=
    弹出栈顶最上面的2个数值 进行计算 a=5 既 a的地址处@0AX处变为5 返回的结果是5 栈为空 结束~这样正常的过程应该是不会完成交换a b 的过程的 只是把b 的值 改为了a的 a的没有变化再看看优化过的执行过程:在红色字体那里 进行乘法运算时 判断到弹出的2个数值中有一个为0
    栈的处理过程应该进行了优化 :
     那就是不返回结果 也不压入这个结果 继续读取后缀表达式队列中的下一个字符 既 读取 + 
    这个时候就执行到了蓝色字体那里 因为判断到有一个运算数为0 这时进行加法计算也是一样优化的过程:
     既不返回结果 也不压入结果 继续读取后缀表达式队列中的下一个字符 既 读取 =此时栈中只剩下(从顶到底)2个值:  (3 @0CX) 和 (5 @0AX) 
    进行赋值运算 :                 既将 @0AX 处的值改为3 最后结束  结果:  @0AX 3       @0CX 5 
    其实我觉得问题出在这里:  
    栈中保存了变量的地址 site 和 值 value
    当进行计算的时候用的是它的value
    但进行赋值的时候   左边部分需要用到它的地址 而右边部分仍然用的是在栈中保存的value 而不是栈中保存的site 所对应的地址的 值
    因此才最终出现这种问题最后 这是我的猜测 因为毕业了找不到以前的书本 也没找到相关资料 
    但我想如果赋值的时候 右边部分再按照保存的地址去取一次值的话 这种问题肯定是不会出现的 恩 写的很乱 估计很多人看不懂
      

  52.   

    int a=13; 
    int b=31; 
    a = b + (b = a) * 0; 中间语言为:   IL_0001:  ldc.i4.s   13 
      IL_0003:  stloc.0 
      IL_0004:  ldc.i4.s   31 
      IL_0006:  stloc.1 
      IL_0007:  ldloc.1 
      IL_0008:  ldloc.0 
      IL_0009:  stloc.1 
      IL_000a:  stloc.0 编译结果实际上就是交换a,b的值,什么乘法,加法都没做。 PS:ldloc - > load local variable onto the stack 
        stloc - > pop value from stack to local variable
    这段代码我不是太清楚 但确实是优化的关系没有做乘法 加法 因为判断有一个运算数为0 就直接跳过了这2步
      

  53.   

    http://topic.csdn.net/t/20060724/02/4899577.html
    确实 这里已经有人把这个给说的很清除了
    好像据这片文章说是只需要2次压栈2次出栈就可以了 
    那就是说 = 赋值那一块操作是不压栈的吧~~只需要把栈操作过程中涉及到的赋值表达式的返回结果压栈就可以了~确实比较厉害 不过感觉有点bug 每个编译环境都是不同的 如果稍微改变一下那块的赋值方式 在这种环境下就不好使了吧
      

  54.   

     语言学习太闷了,就开始有点意思,现在好累
    看样子学计算机不适合我们这些女孩子,但我必需要坚持下去....................................................................................................................................................................
    http://hi.baidu.com/hhh3h