我在torboc 在运行该等式是交换a,b值,但不知道为什会这样。请高手指点下。该等式是怎样一步一步运行。在turboc 此等式一步就运行玩。分开运行就会是不同的结果
解决方案 »
- 我想做一个每月25号操作,请问有什么好的方法么?求赐教
- [原创-欢迎指正]C#操作物理存贮器
- 二进制文件存储数据的问题
- 很新手的问题 VS怎么对数据库的表多表查询操作 单表的我会了
- 钩子问题,wince系统,vs.2005开发,树形控件没法响应鼠标事件,也就是触摸屏事件。
- 如何动态引用webservice
- 如何能获得VS窗口中各控件的ID???
- 在DirectX中如何设置视频捕捉的分辨率?
- C#与VC++相比有哪些缺点?
- 我按VS.NET文档的例子“开发简单WEB服务器控件”,当将源文件FirstControl.cs 编译为.dll文件时出现这种错误:目标类型无效,必须指定“E
- 问一下,VS2005里面的添加现有项,能不能一次性的把整个文件夹加进去?
- 连接access出错,找不到可安装的ISAM
是a和b的交换吗,先进的东西
我交换赋值时都使用个临时变量
解:
1)b=a;
2)b*0
3)b+0
4)a=b+0
5)a=bSo: a=b=a,并没有交换,原来的b不见了。
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
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的值,什么乘法,加法都没做。
-------------------------------------------------------------
为什么是这样啊?
b ^= a;
a ^= b;
+(b=a)*0 ----此处呢?
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
a=b+(b=a)*0
现运算 (b=a)
然后运算 (b=a)*0
最后运算
a=b+(b=a)*0
等同于
b=a;
a=b+a*0;
你连这表达式都没看懂,还谈什么这样运算,如果像你这样想的话早就结贴了。
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
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 直接优化
如果有公司出这种题目,你可以一笑了之。microsoft,ibm,intel这种公司从来不出这种题目的。
还有象什么goto语句在这个语言中有没有,我看到这种题目,掉头就走
当做c程序运行是不交换的,c#程序就交换了。
但是用C#试了一下,结果大吃一惊,交换了.奇怪,又用C++试了一下,没有交换..
毕竟对错不能按编译器说的算吧,逻辑上应该没交换就是没交换,你交换了,不管你是谁都是错的....下面是C++写的(编译器VC6.0):下面是C#写的:
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;
执行步骤:
按优先级编译: 原式: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;二、运算的优先级…………大家应该都明白(在执行过程中也有说明了),不再赘述。
VS2008 C++ 的结果:a=10,b=10
VS2008 C# 的结果:a=20,b=10
最好的方法
a=a^b;
b=a^b;
a=a^b;
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
原因是在于
表达式的解释顺序
在楼主的编译器中
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了,实现了交换最后还是劝楼主不要这么写
除非确定使用的编译器的解释顺序
因为不同的编译器对解释顺序做了一定的优化,
解释顺序顺序不一定相同
结果会因为编译器的不同有所不同
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;
a = a + b;
b = a - b;
a = a - b;可是有意思么,写出来的结果就是让别人给你维护的时候不知道你想干嘛.楼上有位兄弟说得好,如果哪个公司出这样的题目给我做,调头就走.
int a = 3;
int i = a++ * a++ ;这样的技巧一样, 毫无意义.
在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#里面怎么样的.
所以如果你在程序中把 if( b==a ) 写成 if( b=a ) 的话, 那么后者将永远为真, 因为赋值总是为真.
//-------------
如果a=0,还为真吗?
等 级:
发表于: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
无语 井底之蛙
真不知道你能懂什么
计算为b是原B值
b是赋值a后的值
正确的解法是:
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代码。
--------------------------------------------
就这还懂C++,概念一塌糊涂。不要说在a=b+(b=a)*0里编译器不可能什么把b=a“优化”成1,就是在if(b=a)中也不
可能,否则就不是C++或C编译器了而成二百五编译器了。在C++和C中只要是非0值转换为逻辑值都是真,并不需要
为1.
C#中的結果
a=20
b=10
VB.NET中的結果
a=20
b=20
C++中的結果
a=10
b=10
看來有很大的出入,不知道在其它語言上會有什麼變化
如保編譯器有關,那麼C#和VB.Net為什麼也會不同呢
{
static void Main(string[] args)
{
int a = 32;
int b = 16;
a = b + (b = a) * 0;
Console.WriteLine("a="+a+" b="+b);
Console.ReadKey();
}
}
测试了还真是交换了值,真是强。,语言这东西太厉害了!
c++可以如下:
a=a^b^(b=a);
同样11字符完成交换.
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;
对于 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的值。
C#是把这些变量看成值的,所以(b=a)不会把b覆盖;TC里把这些变量看成地址,直接就把a的值放到b对应的地址的内存上去了.
//------------
每个编译器都不大一样吧.
C#是把这些变量看成值的,所以(b=a)不会把b覆盖;TC里把这些变量看成地址,直接就把a的值放到b对应的地址的内存上去了.
//------------
[(b=a)不会把b覆盖]:那它们还怎么交换值呢?你不会是说在表达式a=b+(b=a)*0执行完后才执行的(b=a)吧???
当时汇编挂了 唉
那段反汇编的代码没有看懂不过表达式的计算是在栈中进行处理的(好像是数据结构的内容)
没有优化过的代码
具体的执行过程有个如下:( 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 所对应的地址的 值
因此才最终出现这种问题最后 这是我的猜测 因为毕业了找不到以前的书本 也没找到相关资料
但我想如果赋值的时候 右边部分再按照保存的地址去取一次值的话 这种问题肯定是不会出现的 恩 写的很乱 估计很多人看不懂
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步
确实 这里已经有人把这个给说的很清除了
好像据这片文章说是只需要2次压栈2次出栈就可以了
那就是说 = 赋值那一块操作是不压栈的吧~~只需要把栈操作过程中涉及到的赋值表达式的返回结果压栈就可以了~确实比较厉害 不过感觉有点bug 每个编译环境都是不同的 如果稍微改变一下那块的赋值方式 在这种环境下就不好使了吧
看样子学计算机不适合我们这些女孩子,但我必需要坚持下去....................................................................................................................................................................
http://hi.baidu.com/hhh3h