昨日写了个appWidget 的demo 优化代码的时候偶然写出了一句 num = (num++)%3;的代码,结果出现了莫名奇妙的问题。我尝试对上一句代码循环几次,发现num 的值一直都是0;
百思不得其解下写了个demo 验证,demo如下。 环境java 6.0;
public class testpro {
public static void main(String[] args) {
int num = 0;
while(num < 2) {
//num = (num++)%3;
num = num++;
}
}
}
PS: 如果如上写的代码就会出现死循环,因为num 的值一直为0; 而同样的代码在gcc 编译通过 运行结果正常。
查看java 的 bytecode 如下:
Compiled from "testpro.java"
public class testpro extends java.lang.Object{
public testpro();
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
1: istore_1
2: iload_1
3: iconst_3
4: if_icmpge 15
7: iload_1
8: iinc 1, 1
11: istore_1
12: goto 2
15: return
}
上面的代码分析
1. i_const_0 //把int 类型的常量0 压入操作数的栈顶。
2. istore_1 //把操作数栈的栈顶出栈,并存入局部变量中。
3. iload_1 //把局部变量中的第一个值 复制到操作数栈中。
4. iconst_3 //把常量3压入操作数栈顶,
5. if_icmpge // 此操作是将操作数栈顶的两个值出栈,比较值1和值2的大小,如果值2大于等于值1 则跳转到 15 执行。
6. iload_1 //把变量1的值压入操作栈的栈顶。
7. iinc 1,1 //变量1 的值加1 从0 变成了1. 但是此时操作栈栈顶的值依然是 刚才压入栈的0!
8. istore_1 //这个操作又把操作栈的栈顶出栈赋值给了变量。 这个时候 变量的值有被从1 赋值成0了。 画外音:这不科学啊,这毁三观啊!
9. 跳到2 循环。
这真的不科学啊~~~~~~~~~~ java 你肿么可以这么不科学呢?!
好吧,只能怪自己怎么写出了这么不科学的代码- -!。
下附 类似代码在gcc下编译出的结果。
int main() {
int num = 0;
while(num < 2) {
num = num++;
}
return 0;
}
以上代码运行正常, num可以增加,while运行两次后推出循环。
下附 gcc -s 之后编译出来的汇编文件
.file "test.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl $0, -4(%rbp) //对 %rbp-4 的地址进行赋值 0
jmp .L2
.L3:
addl $1, -4(%rbp) //对 %rbp-4 的地址进行加1赋值
.L2:
cmpl $1, -4(%rbp) //而进行比较的时候, 取的值也是%rbp-4 的地址的值。
jle .L3
movl $0, %eax
leave
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.4.6-11ubuntu2) 4.4.6"
.section .note.GNU-stack,"",@progbits
相比java而言,逻辑清晰明了。