昨日写了个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而言,逻辑清晰明了。