首先贴一个非常简洁却不简单的代码:
Java(jdk1.6) 代码 (C++代码类似,采用GNU的g++编译器)
public class Test{
public static void main(String[] args){
int a=0;
a = a++;
System.out.println(a);
}
}
思考一个问题,这个程序a的输出是多少呢?
… …
最开始的想法是这样的,++自增运算符在这里是后缀式,应该是a赋值给a之后,a再自增一次,即首先a=a,然后a++(a=a+1).如此,最后a的输出值应该是1.
但是,不管是C++(g++编译器)还是Java(jdk1.6),运行的结果让我很惊讶,a的输出为0!这是为什么?csufox经过一段时间的思考,得出了以下的一些认识.
搜索了很多资料,网上有人给出的解释大致如下:++运算符的优先级高于赋值运算符,在程序运行a++时,a的值首先是赋值给一个拷贝或者说临时变量(按值传递,底层实现),即temp=a(即temp=a=0),然后a执行自增运算(运算后a的值为1),最后将这个拷贝(此时拷贝的值为0)作为(a++)整体的值赋值给a(赋值后a的值有重新从1变为0),所以最终的a的值输出为0.即a=a++;语句等价于 a=(temp=a,a+=1,temp);
但是这个解释实在是牵强,底层依然不清楚是具体怎么做的,为什么需要有临时变量?并不能让人信服.下面csufox将从Java的字节码指令来更清楚地了解其细节.
用javap命令反编译上述代码的字节码文件,得到如下信息(附解释):
D:\java>javap -c Test
Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_0 //将常量'0'push入操作数栈(operand stack,与普通栈不同)
1: istore_1 //将常量'0'存储到栈(注意不是堆,局部变量存储在栈中)
2: iload_1 //将常量'0'载入到操作数栈
3: iinc 1, 1 //在栈中将a增1,a从'0'变为'1'
6: istore_1 //在操作数栈中将常量''重新存储到栈,a从'1'变回'0'
7: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
14: return
}
而看看a=++a;的字节码指令:(该代码的a的输出显然是1)
Code:
0: iconst_0
1: istore_1
2: iinc 1, 1 //不同点*
5: iload_1 //不同点*
6: istore_1
7: getstatic
10: iload_1
11: invokevirtual
14: return
我们可以看出不同点就是一个是先载入再自增运算;一个是先自增运算后,再载入新值.
综上可知,iinc字节码指令每次执行时都是从栈中直接执行,而不是在操作数栈中执行.
- 在i=i++的情况下,变量a已经在栈中改变,但是在操作数栈中依然保留原值;
- 在i=++i的情况下,变量a已经在栈中改变,但是在操作数栈中载入的是改变后的新值.
以上是Java对代码输出的解释.C++的解释依然不得而知,将来csufox准备看汇编吧.
参考:
Java字节码及字节码指令: http://www.ibm.com/developerworks/ibm/library/it-haggar_bytecode/
Java虚拟机规范: http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html
细节决定深度
转自:http://www.csufox.com/a-plus-plus.html
相关推荐
这使得 `a+b++` 等同于 `(a+b)+b++`,而 `a+++b` 实际上是 `(a++)+b`。另一方面,后缀运算符的优先级较低,如在 `a*b++` 中,`b` 的值会在乘法运算之后被增加。 对于逻辑运算,自增自减运算符与逻辑运算符(如 `&&`...
Java语言中的自增运算符(++)和自减运算符(--)是两个非常基础且独特的运算符,它们在编程中用于递增或递减变量的值。这两个运算符源自C语言,且Java语言中也使用了这两个运算符,并保留了它们的主要特性,但也有一些...
在C++编程语言中,`sizeof`运算符、自增`++`和自减`--`运算符是程序员日常工作中非常常见的元素。了解并熟练掌握它们的使用是编写高效、准确代码的关键。让我们深入探讨这些知识点。 首先,`sizeof`运算符用于计算...
自增运算符(++)用于将变量的值增加1,而自减运算符(--)则是将变量的值减少1。这两种运算符分为前缀形式(++x或--x)和后缀形式(x++或x--),它们在操作顺序和结果上有所不同。 前缀形式的自增和自减运算符(如...
这篇文章将详细地介绍自增和自减运算符的使用功能、使用形式以及它们在复杂表达式中的应用,以帮助初学者深入理解并正确使用这两个运算符。 首先,自增和自减运算符都只作用于变量,不能作用于常量或表达式。例如,...
因此,需要深入理解自增(自减)运算符的运算规律和应用场景。 C语言中的自增(自减)运算符是一个非常重要的知识点,需要深入理解和掌握。在编程过程中,需要正确地使用自增(自减)运算符,以提高程序的执行效率和简洁...
自增运算符`++`和自减运算符`--`有前置和后置两种形式,这使得它们在某些情况下表现出不同的行为。 前置自增/自减运算符(如 `++a` 或 `--a`)会先改变变量的值,然后返回新值。这意味着如果这个表达式用在其他运算...
此外,还需注意运算符的副作用,如自增自减运算符对变量的即时影响,以及可能出现的溢出问题,特别是在处理大数值时。 总的来说,本章将深入讲解这些基本概念,通过实例演示各种运算符的用法,并探讨它们在实际编程...
在C语言中,自加运算符(`++`)是一个重要的...在教授这部分内容时,教师应鼓励学生通过实践和编写代码来深入理解这些概念,而不是仅仅依赖于简单的规则总结。这样才能确保学生能正确地掌握C语言中自加运算符的使用。
),位运算符(&,|,^,~,,>>),赋值运算符(=,+=,-=,*=,/=,%=),自增自减运算符(++,--)等。每个运算符都有特定的作用和使用场景。 2. **运算符的优先级与结合性**:运算符的优先级决定了运算的顺序,...
在C语言的开发中,自增运算符问题是不少程序员经常会遇到的一个问题,尤其是对初学者而言,常常会因为对它的理解不深而导致程序运行出现错误或者出现逻辑上的偏差。解析C语言中自增运算符问题是非常必要的,它涉及到...
6. 自增运算符 (++):增加一个整数值,可以是前缀(`++a`)或后缀形式(`a++`)。 7. 自减运算符 (--): 减少一个整数值,同样可以是前缀(`--a`)或后缀形式(`a--`)。 在上述代码示例中,可以看到这些运算符如何...
自增和自减运算符(++ 和 --)用于改变变量的值。`++` 运算符使变量增加1,而 `--` 运算符则使其减少1。它们有两种形式:前缀(前置)和后缀(后置)。 - 前缀运算符:如 `++i`,首先将变量i的值增加1,然后返回新...
自增运算符`++`和自减运算符`--`可以在变量前缀或后缀使用,它们会立即改变变量的值并返回新的值。前缀自增/自减(如`++a`、`--a`)会先增加或减少变量,然后返回新值。后缀自增/自减(如`a++`、`a--`)先返回变量的...
自增自减运算符`++`和`--`用于增加或减少变量的值。前缀形式如`++a`先增加后使用,而后缀形式如`a++`先使用后增加。例如,`int x = 1; ++x;`会使x变为2。 八、类型转换运算符 类型转换运算符允许我们显式地将一种...
- (D) `(++a) += (a++)`:先自增a,然后进行加法操作,但a++在加法后还会再次自增,a的值变为11。 2. `sizeof`运算符的使用: `sizeof`用于计算变量或类型的大小(以字节为单位)。 - `sizeof(str)`:字符串常量...
6. **自增自减运算符**:++和--。它们可以放在变量前(前缀)或后(后缀),例如`a++;`或`++a;`。 7. **条件运算符**(三元运算符):`? :`。例如,`int max = (a > b) ? a : b;`表示如果a大于b,max等于a,否则...
- 自增`++`和自减`--`运算符的前置形式(如`++a`)会先改变变量的值再进行运算,而后置形式(如`a++`)则会在运算后改变变量的值。 5. 三元运算符和逗号运算符: - 例如`(x=a*b , x+x , x*x)`,x的最终值取决于...
实验中给出的表达式如`b+a+++a`、`b+(a++)+a`等展示了复合赋值运算符和自增运算符的组合使用。这些表达式可能会导致混淆,因为它们依赖于运算符的优先级和结合性。例如,`b+a+++a`的解析可能因解释器的不同而不同,...
这些题目要求对C语言的运算符有深入理解,包括它们的操作方式和返回结果。例如,位运算符&用于逐位比较两个数,逻辑运算符&&则用于逻辑判断,只有当两边的表达式都为真时,结果才为真。 总的来说,本章的学习旨在...