i++原理分析

今天遇到同学提出了一个题目,如下:
下列程序输出结果为:

#include<stdio.h>
int main(){
    char a[] = "123" ,*p;
    p = a ; 
    printf("%c%c%c\n", *p++,*p++,*p++); 
    return 0 ; 
}

我觉得是111,但是实际上结果为123
这里写图片描述
我对C和C++了解并不是很深入,解释不了原因,然后我去用java试了试。
这道题我们主要的错误点在于对于++的理解,我就在java中只测试++,忽略题中对于指针的考察。
代码如下:

public class App 
{
    public static void main( String[] args )
    {
        int i = 1;
        System.out.println(i+++","+i+++","+i++);
    }
}

我认为会是1,1,1但还是1,2,3。其实之前只是知道i++是后加,但并不知道是在什么后加一。
于是去看一下字节码探个究竟:
上面程序的字节码如下:

Classfile /Users/zjchai/CodeSpace/Workspace/Maven/TestArchetype/target/classes/jack/test/App.class
  Last modified 2016-3-23; size 768 bytes
  MD5 checksum ea64c6e591bb2f46ea1f8ddc43509c91
  Compiled from "App.java"
public class jack.test.App
  minor version: 3
  major version: 45
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #11.#27        // java/lang/Object."<init>":()V
   #2 = Fieldref           #28.#29        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = Class              #30            // java/lang/StringBuffer
   #4 = Methodref          #3.#27         // java/lang/StringBuffer."<init>":()V
   #5 = Methodref          #3.#31         // java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer;
   #6 = String             #32            // ,
   #7 = Methodref          #3.#33         // java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
   #8 = Methodref          #3.#34         // java/lang/StringBuffer.toString:()Ljava/lang/String;
   #9 = Methodref          #35.#36        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #10 = Class              #37            // jack/test/App
  #11 = Class              #38            // java/lang/Object
  #12 = Utf8               <init>
  #13 = Utf8               ()V
  #14 = Utf8               Code
  #15 = Utf8               LineNumberTable
  #16 = Utf8               LocalVariableTable
  #17 = Utf8               this
  #18 = Utf8               Ljack/test/App;
  #19 = Utf8               main
  #20 = Utf8               ([Ljava/lang/String;)V
  #21 = Utf8               args
  #22 = Utf8               [Ljava/lang/String;
  #23 = Utf8               i
  #24 = Utf8               I
  #25 = Utf8               SourceFile
  #26 = Utf8               App.java
  #27 = NameAndType        #12:#13        // "<init>":()V
  #28 = Class              #39            // java/lang/System
  #29 = NameAndType        #40:#41        // out:Ljava/io/PrintStream;
  #30 = Utf8               java/lang/StringBuffer
  #31 = NameAndType        #42:#43        // append:(I)Ljava/lang/StringBuffer;
  #32 = Utf8               ,
  #33 = NameAndType        #42:#44        // append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
  #34 = NameAndType        #45:#46        // toString:()Ljava/lang/String;
  #35 = Class              #47            // java/io/PrintStream
  #36 = NameAndType        #48:#49        // println:(Ljava/lang/String;)V
  #37 = Utf8               jack/test/App
  #38 = Utf8               java/lang/Object
  #39 = Utf8               java/lang/System
  #40 = Utf8               out
  #41 = Utf8               Ljava/io/PrintStream;
  #42 = Utf8               append
  #43 = Utf8               (I)Ljava/lang/StringBuffer;
  #44 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuffer;
  #45 = Utf8               toString
  #46 = Utf8               ()Ljava/lang/String;
  #47 = Utf8               java/io/PrintStream
  #48 = Utf8               println
  #49 = Utf8               (Ljava/lang/String;)V
{
  public jack.test.App();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Ljack/test/App;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=2, args_size=1
         0: iconst_1
         1: istore_1
         2: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         5: new           #3                  // class java/lang/StringBuffer
         8: dup
         9: invokespecial #4                  // Method java/lang/StringBuffer."<init>":()V
        12: iload_1
        13: iinc          1, 1
        16: invokevirtual #5                  // Method java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer;
        19: ldc           #6                  // String ,
        21: invokevirtual #7                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
        24: iload_1
        25: iinc          1, 1
        28: invokevirtual #5                  // Method java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer;
        31: ldc           #6                  // String ,
        33: invokevirtual #7                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
        36: iload_1
        37: iinc          1, 1
        40: invokevirtual #5                  // Method java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer;
        43: invokevirtual #8                  // Method java/lang/StringBuffer.toString:()Ljava/lang/String;
        46: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        49: return
      LineNumberTable:
        line 7: 0
        line 8: 2
        line 9: 49
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      50     0  args   [Ljava/lang/String;
            2      48     1     i   I
}
SourceFile: "App.java"

这个挺烦的,我们只看public static void main(java.lang.String[]);之后的code结合上面的Constant pool。
按照代码序号依次解释什么意思:
0:将1入操作数据栈;
1:将栈顶元素保存到第一个临时变量(i);
2,5不解释
8:是为9的构造函数准备的;
12:将第一个临时变量(i)的值入栈;
13:将第一个临时变量加1,不影响栈,即在临时变量区自加;
16,19,21:不解释了,就是执行append方法把栈顶数据加进去此时这个数值为1,局部变量区的数值是2了已经;
24:即又是把第一个临时变量(i)的值(2)入栈;
25:又是局部变量的第一个元素(i)自己加一变成3了,且不影响栈;
。。。
我相信下面就都会了。
因此我们可以看到,++为后缀的话,从字节码的角度上看是执行完load之后加一。如果为前缀我试了,就是在load之前,有兴趣可以自己试一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值