C、C++、Java异或运算交换变量变量值的区别
2014-05-06 23:54
309 查看
今天看到一位大神的博客,深受感触。决定也发一篇博客,证明一下我还活着。
于是我翻看以前学习时做的一些笔记,整理了一下,得到了一个关于异或运算交换变量变量值的笔记。
首先来看下面三组表达式,看起来他们都能实现交换两个变量的值。
可实际的情况是,前面2组表达式,在C、C++、Java中都能顺利完成变量值的交换。而第3组表达式,却只在C、C++中通过了,而在Java中却得到了意料之外的结果。请看下面的截图
在C、C++中得到了想要的结果
而在Java中,却得到了这样的结果
怎么样,是不是很惊讶,在java中,a的值,换给了b,但不管怎么做,a的值都是0,怎么会这样?百思不得其解。这事就此搁了下来。
过了很长时间之后,在意个偶然的机会中,我在一个关于Java谜题的手册中看到了这个问题,原来这还是Java比较经典的谜题之一了。
原来,事情是这样的。
很久以前,当中央处理器只有少数寄存器时,人们发现可以通过利用异或操作符(^)的属性(x ^ y ^ x) == y来避免使用临时变量,这个惯用法曾经在C编程语言中被使用过,并进一步被融入到了C++中,但是它并不保证都可以正确运行。但是有一点可以肯定:它在Java中肯定是不能正确运行的。
Java语言规范描述到:操作符的操作数是从左向右求值的。为了求表达式 x ^= expr的值,x的值是在计算expr之前被提取的,并且这两个值的异或结果被赋给变量x。在OprDemo程序中,变量x的值被提取了两次——每次在表达式中出现时都提取一次——但是两次提取都发生在所有的赋值操作之前。
下面的代码可以很好的解释其原理,并且解释了为什么会得到这样的结果
从上面的代码可以看出,其实a之所以会为0,是因为a^a造成的,我们知道,两个相同的值异或其值为0.
在C和C++中,并没有指定表达式的计算顺序。当运行表达式x^=expr时,许多C和C++编译器是在计算expr之后才提取x的值的,这使得上述的做法可以得到正确的结果。
那么在Java中,有没有办法使得不使用中间变量的单个表达式来达到这个目的呢?这是可以的,请看下面的代码。
写这么多,最后想说的就是在单个的表达式中不要对同一变量赋值两次,赋值次数多了,就会引起混乱。
于是我翻看以前学习时做的一些笔记,整理了一下,得到了一个关于异或运算交换变量变量值的笔记。
首先来看下面三组表达式,看起来他们都能实现交换两个变量的值。
a = a ^ b; b = a ^ b; a = a ^ b;
a = a ^ (b = b ^ (a = a ^ b));
a ^= b ^= a ^= b;
可实际的情况是,前面2组表达式,在C、C++、Java中都能顺利完成变量值的交换。而第3组表达式,却只在C、C++中通过了,而在Java中却得到了意料之外的结果。请看下面的截图
在C、C++中得到了想要的结果
而在Java中,却得到了这样的结果
怎么样,是不是很惊讶,在java中,a的值,换给了b,但不管怎么做,a的值都是0,怎么会这样?百思不得其解。这事就此搁了下来。
过了很长时间之后,在意个偶然的机会中,我在一个关于Java谜题的手册中看到了这个问题,原来这还是Java比较经典的谜题之一了。
原来,事情是这样的。
很久以前,当中央处理器只有少数寄存器时,人们发现可以通过利用异或操作符(^)的属性(x ^ y ^ x) == y来避免使用临时变量,这个惯用法曾经在C编程语言中被使用过,并进一步被融入到了C++中,但是它并不保证都可以正确运行。但是有一点可以肯定:它在Java中肯定是不能正确运行的。
Java语言规范描述到:操作符的操作数是从左向右求值的。为了求表达式 x ^= expr的值,x的值是在计算expr之前被提取的,并且这两个值的异或结果被赋给变量x。在OprDemo程序中,变量x的值被提取了两次——每次在表达式中出现时都提取一次——但是两次提取都发生在所有的赋值操作之前。
下面的代码可以很好的解释其原理,并且解释了为什么会得到这样的结果
// Java中x^= y^= x^= y的实际行为 int tmp1 = x ; // x在表达式中第一次出现 int tmp2 = y ; // y的第一次出现 int tmp3 = x ^ y ; // 计算x ^ y x = tmp3 ; // 最后一个赋值:存储x ^ y 到 x y = tmp2 ^ tmp3 ; // 第二个赋值:存储最初的x值到y中 x = tmp1 ^ y ; // 第一个赋值:存储0到x中
从上面的代码可以看出,其实a之所以会为0,是因为a^a造成的,我们知道,两个相同的值异或其值为0.
在C和C++中,并没有指定表达式的计算顺序。当运行表达式x^=expr时,许多C和C++编译器是在计算expr之后才提取x的值的,这使得上述的做法可以得到正确的结果。
那么在Java中,有没有办法使得不使用中间变量的单个表达式来达到这个目的呢?这是可以的,请看下面的代码。
y = (x^= (y^= x))^ y ;这句代码就能够做到
写这么多,最后想说的就是在单个的表达式中不要对同一变量赋值两次,赋值次数多了,就会引起混乱。
相关文章推荐
- C、C++、Java异或运算交换变量变量值的区别
- 如何不利用一个额外的变量来达到交换两个变量值的目的-------位上的异或运算
- 如何不利用一个额外的变量来达到交换两个变量值的目的-------位上的异或运算
- JAVA和C++ 交换两个变量的值的函数 区别
- 如何不利用一个额外的变量来达到交换两个变量值的目的-------位上的异或运算
- java中把两个变量进行值交换,通过异或两次运算就能实现值互换。
- 异或运算交换两个变量的值
- 用异或运算交换连个变量
- 网络误区:不用中间变量交换2个变量的value,最高效的是异或运算.
- 在不借助第三方变量情况下实现两个变量的交换(借助于异或运算)
- 通过异或运算实现两个变量的交换(不需借助第三个变量)
- java 与 c++ 关于局部变量重命名的区别
- C/C++/Java不使用临时变量实现两个数的交换
- 程序设计中利用“按位异或”运算交换两个变量的值原理
- 位运算的异或来交换变量
- 剑指Offer(Java版):不用第三个变量就能交换两个变量值
- Java笔记:位运算之异或交换数值原理
- 为什么异或运算可以实现两个整数的交换,而无需借助第3个临时变量
- 深入理解异或运算 xor 的含义——再探不使用加减乘除实现加法运算、不使用额外空间交换两个变量的值
- Java学习--(三)变量与常量与与C++的一些区别