博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
有趣的++i和i++
阅读量:6077 次
发布时间:2019-06-20

本文共 4100 字,大约阅读时间需要 13 分钟。

  作为一个天天和代码“约会”的人来说i++和++i这玩意再熟悉不过了,因为使用频率太高了。

虽然如此,但也未必见得我们真的了解她,不妨猜猜下面的输出结果。

1 #inlcude 
2 3 int main(void) 4 { 5 int i = 0, j = 0; 6 7 printf("i[1] = %d i[2] = %d\n", i++ + ++i, ++i + i++); 8 9 printf("j[1] = %d j[2] = %d\n", j++ + j++, ++j + ++j);10 11 return 0;12 }

  

  最后结果是:

  i[1] = 6 i[2] = 2

  j[1] = 4 j[2] = 4

  想要得出正确答案,仅仅知道前+和后+的区别是不够的,这里面有两个坑。

  第一个是cpu处理前+和后+真正的执行过程。

  第二个是printf这个“小妾”暗藏一腿。

  先把简单的第二个坑填了,以一般的思维和习惯会下意识的认为printf先计算前面那个表达式(即代码中的i[1] 和 j[1]),然后计算后面那个表达式的值(即  代码中的i[2]和j[2]),事实却正好相反,要先算后面再算前面。

  要想填平第一个大坑,我们需要研究编译后的汇编代码。

  

1  @by tid_think 2  @arm-linux-gcc -S test.c -o test.s 3  @tiny4412 4     .cpu arm1176jzf-s 5     .eabi_attribute 27, 3 6     .fpu vfp 7     .eabi_attribute 20, 1 8     .eabi_attribute 21, 1 9     .eabi_attribute 23, 310     .eabi_attribute 24, 111     .eabi_attribute 25, 112     .eabi_attribute 26, 213     .eabi_attribute 30, 614     .eabi_attribute 18, 415     .file    "test.c"16     .section    .rodata17     .align    218 .LC0:19     .ascii    "i[1] = %d i[2] = %d\012\000"20     .align    221 .LC1:22     .ascii    "j[1] = %d j[2] = %d\012\000"23     .text24     .align    225     .global    main26     .type    main, %function27 main:28     @ args = 0, pretend = 0, frame = 829     @ frame_needed = 1, uses_anonymous_args = 030         31                               @by tid_think32                               @关键代码33     stmfd    sp!, {fp, lr}    @将fp,lr两个寄存器的值压栈34     add    fp, sp, #4         @fp = sp + 435     sub    sp, sp, #8         @sp = sp + 836     mov    r3, #0             @r3 = 037     str    r3, [fp, #-8]      @将r3的值(0)写入 fp -8 的地方 int i = 038     mov    r3, #0             @r3 = 039     str    r3, [fp, #-12]     @将r3的值(0)写入 fp -12 的地方 int j = 040     ldr    r1, .L2            @将.L2的地址加载到r141     ldr    r3, [fp, #-8]      @将fp -8地址上的值(i = 0) 给r342     add    r3, r3, #1         @r3 = r3 + 1   ===>i = 143     str    r3, [fp, #-8]      @将r3的值(1)写入 fp -8 的地方 i44     ldr    r2, [fp, #-8]      @将fp -8地址上的值(i = 1) 给r245     ldr    r3, [fp, #-8]      @将fp -8地址上的值(i = 1) 给r346     add    r2, r2, r3         @r2 = r2 + r 3 = 2 47     ldr    r3, [fp, #-8]      @将fp -8地址上的值(i = 1) 给r348     add    r3, r3, #1         @ r3 = r3 + 1 = 249     str    r3, [fp, #-8]      @将r3的值(2)写入 fp -8 的地方 i50     ldr    r3, [fp, #-8]      @将fp -8地址上的值(i = 2) 给r351     add    r3, r3, #1         @ r3 = r3 + 1 = 352     str    r3, [fp, #-8]      @将r3的值(3)写入 fp -8 的地方 i53     ldr    r0, [fp, #-8]      @将fp -8地址上的值(i = 3) 给r054     ldr    r3, [fp, #-8]      @将fp -8地址上的值(i = 3) 给r355     add    r3, r0, r3         @ r3 = r0 + r3 = 656     ldr    r0, [fp, #-8]      @将fp -8地址上的值(i = 3) 给r057     add    r0, r0, #1         @r0 = r0 + 1 = 458     str    r0, [fp, #-8]      @将r0的值(4)写入 fp -8 的地方59     mov    r0, r1             @r0 = r1    给printf传参数1 60     mov    r1, r2             @r1 = r2 = 2   给printf传参数2 61     mov    r2, r3             @r2 = r3 = 6   给printf传参数362     bl    printf              @调用printf打印63     ldr    r1, .L2+4          @开始计算j了............64     ldr    r2, [fp, #-12]65     ldr    r3, [fp, #-12]66     add    r2, r2, r367     ldr    r3, [fp, #-12]68     add    r3, r3, #169     str    r3, [fp, #-12]70     ldr    r3, [fp, #-12]71     add    r3, r3, #172     str    r3, [fp, #-12]73     ldr    r3, [fp, #-12]74     add    r3, r3, #175     str    r3, [fp, #-12]76     ldr    r3, [fp, #-12]77     add    r3, r3, #178     str    r3, [fp, #-12]79     ldr    r0, [fp, #-12]80     ldr    r3, [fp, #-12]81     add    r3, r0, r382     mov    r0, r183     mov    r1, r284     mov    r2, r385     bl    printf86     mov    r3, #087     mov    r0, r388     sub    sp, fp, #489     ldmfd    sp!, {fp, pc}90 .L3:91     .align    292 .L2:93     .word    .LC094     .word    .LC195     .size    main, .-main96     .ident    "GCC: (ctng-1.8.1-FA) 4.5.1"97     .section    .note.GNU-stack,"",%progbits

 

 

汇编代码解析:

  首先刨去没用的信息,直接从 31行开始看

  33~35行都是对栈指针的一些偏移和保存。

  从以上汇编代码看可以看出简单的两句C编译成汇编就是一大坨,如果用纯汇编写15行左右应该就能搞定 执行效率几乎是C的20倍……………………

 

转载于:https://www.cnblogs.com/tid-think/p/5136574.html

你可能感兴趣的文章
tomcat多应用之间如何共享jar
查看>>
Flex前后台交互,service层调用后台服务的简单封装
查看>>
MySQL入门12-数据类型
查看>>
Windows Azure 保留已存在的虚拟网络外网IP(云服务)
查看>>
修改字符集
查看>>
HackTheGame 攻略 - 第四关
查看>>
js删除数组元素
查看>>
带空格文件名的处理(find xargs grep ..etc)
查看>>
华为Access、Hybrid和Trunk的区别和设置
查看>>
centos使用docker下安装mysql并配置、nginx
查看>>
关于HTML5的理解
查看>>
需要学的东西
查看>>
Internet Message Access Protocol --- IMAP协议
查看>>
Linux 获取文件夹下的所有文件
查看>>
对 Sea.js 进行配置(一) seajs.config
查看>>
第六周
查看>>
解释一下 P/NP/NP-Complete/NP-Hard 等问题
查看>>
javafx for android or ios ?
查看>>
微软职位内部推荐-Senior Software Engineer II-Sharepoint
查看>>
sql 字符串操作
查看>>