有趣的++i和i++
作为一个天天和代码“约会”的人来说i++和++i这玩意再熟悉不过了,因为使用频率太高了。
虽然如此,但也未必见得我们真的了解她,不妨猜猜下面的输出结果。
#inlcude <stdio.h> int main(void)
{
int i = , j = ; printf("i[1] = %d i[2] = %d\n", i++ + ++i, ++i + i++); printf("j[1] = %d j[2] = %d\n", j++ + j++, ++j + ++j); return ;
}
最后结果是:
i[1] = 6 i[2] = 2
j[1] = 4 j[2] = 4
想要得出正确答案,仅仅知道前+和后+的区别是不够的,这里面有两个坑。
第一个是cpu处理前+和后+真正的执行过程。
第二个是printf这个“小妾”暗藏一腿。
先把简单的第二个坑填了,以一般的思维和习惯会下意识的认为printf先计算前面那个表达式(即代码中的i[1] 和 j[1]),然后计算后面那个表达式的值(即 代码中的i[2]和j[2]),事实却正好相反,要先算后面再算前面。
要想填平第一个大坑,我们需要研究编译后的汇编代码。
@by tid_think
@arm-linux-gcc -S test.c -o test.s
@tiny4412
.cpu arm1176jzf-s
.eabi_attribute ,
.fpu vfp
.eabi_attribute ,
.eabi_attribute ,
.eabi_attribute ,
.eabi_attribute ,
.eabi_attribute ,
.eabi_attribute ,
.eabi_attribute ,
.eabi_attribute ,
.file "test.c"
.section .rodata
.align
.LC0:
.ascii "i[1] = %d i[2] = %d\012\000"
.align
.LC1:
.ascii "j[1] = %d j[2] = %d\012\000"
.text
.align
.global main
.type main, %function
main:
@ args = , pretend = , frame =
@ frame_needed = , uses_anonymous_args = @by tid_think
@关键代码
stmfd sp!, {fp, lr} @将fp,lr两个寄存器的值压栈
add fp, sp, # @fp = sp +
sub sp, sp, # @sp = sp +
mov r3, # @r3 =
str r3, [fp, #-] @将r3的值()写入 fp - 的地方 int i = 0
mov r3, # @r3 =
str r3, [fp, #-] @将r3的值()写入 fp - 的地方 int j = 0
ldr r1, .L2 @将.L2的地址加载到r1
ldr r3, [fp, #-] @将fp -8地址上的值(i = ) 给r3
add r3, r3, # @r3 = r3 + ===>i =
str r3, [fp, #-] @将r3的值()写入 fp - 的地方 i
ldr r2, [fp, #-] @将fp -8地址上的值(i = ) 给r2
ldr r3, [fp, #-] @将fp -8地址上的值(i = ) 给r3
add r2, r2, r3 @r2 = r2 + r =
ldr r3, [fp, #-] @将fp -8地址上的值(i = ) 给r3
add r3, r3, # @ r3 = r3 + =
str r3, [fp, #-] @将r3的值()写入 fp - 的地方 i
ldr r3, [fp, #-] @将fp -8地址上的值(i = ) 给r3
add r3, r3, # @ r3 = r3 + =
str r3, [fp, #-] @将r3的值()写入 fp - 的地方 i
ldr r0, [fp, #-] @将fp -8地址上的值(i = ) 给r0
ldr r3, [fp, #-] @将fp -8地址上的值(i = ) 给r3
add r3, r0, r3 @ r3 = r0 + r3 =
ldr r0, [fp, #-] @将fp -8地址上的值(i = ) 给r0
add r0, r0, # @r0 = r0 + =
str r0, [fp, #-] @将r0的值()写入 fp - 的地方
mov r0, r1 @r0 = r1 给printf传参数1
mov r1, r2 @r1 = r2 = 给printf传参数2
mov r2, r3 @r2 = r3 = 给printf传参数3
bl printf @调用printf打印
ldr r1, .L2+4 @开始计算j了............
ldr r2, [fp, #-]
ldr r3, [fp, #-]
add r2, r2, r3
ldr r3, [fp, #-]
add r3, r3, #
str r3, [fp, #-]
ldr r3, [fp, #-]
add r3, r3, #
str r3, [fp, #-]
ldr r3, [fp, #-]
add r3, r3, #
str r3, [fp, #-]
ldr r3, [fp, #-]
add r3, r3, #
str r3, [fp, #-]
ldr r0, [fp, #-]
ldr r3, [fp, #-]
add r3, r0, r3
mov r0, r1
mov r1, r2
mov r2, r3
bl printf
mov r3, #
mov r0, r3
sub sp, fp, #
ldmfd sp!, {fp, pc}
.L3:
.align
.L2:
.word .LC0
.word .LC1
.size main, .-main
.ident "GCC: (ctng-1.8.1-FA) 4.5.1"
.section .note.GNU-stack,"",%progbits
汇编代码解析:
首先刨去没用的信息,直接从 31行开始看
33~35行都是对栈指针的一些偏移和保存。
从以上汇编代码看可以看出简单的两句C编译成汇编就是一大坨,如果用纯汇编写15行左右应该就能搞定 执行效率几乎是C的20倍……………………
有趣的++i和i++的更多相关文章
- 谈谈一些有趣的CSS题目(十二)-- 你该知道的字体 font-family
开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...
- 谈谈一些有趣的CSS题目(十一)-- reset.css 知多少?
开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...
- 几个有趣的WEB设备API(二)
浏览器和设备之间还有很多有趣的接口, 1.屏幕朝向接口 浏览器有两种方法来监听屏幕朝向,看是横屏还是竖屏. (1)使用css媒体查询的方法 /* 竖屏 */ @media screen and (or ...
- 谈谈一些有趣的CSS题目(三)-- 层叠顺序与堆栈上下文知多少
开本系列,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉 ...
- 谈谈一些有趣的CSS题目(一)-- 左边竖条的实现方法
开本系列,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉 ...
- 谈谈一些有趣的CSS题目(二)-- 从条纹边框的实现谈盒子模型
开本系列,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉 ...
- 谈谈一些有趣的CSS题目(四)-- 从倒影说起,谈谈 CSS 继承 inherit
开本系列,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉 ...
- 谈谈一些有趣的CSS题目(五)-- 单行居中,两行居左,超过两行省略
开本系列,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉 ...
- 谈谈一些有趣的CSS题目(六)-- 全兼容的多列均匀布局问题
开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...
- 谈谈一些有趣的CSS题目(七)-- 消失的边界线问题
开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...
随机推荐
- [JSP] c:forEach 如何输出序号 - luotangsha的专栏 - 博客频道 - CSDN.NET
[JSP] c:forEach 如何输出序号 分类: JSP 2011-06-24 01:36 13018人阅读 评论(2) 收藏 举报 jspcbordertable 关键在于<c:forEa ...
- Jsoup使用教程
一.解析和遍历一个HTML文档1.解析Html及Url链接 String html = "<html><head><title>First parse&l ...
- 异常捕获拒绝闪退 让应用从容的崩溃UncaughtExceptionHandler
虽然大家都不愿意看到程序崩溃,但可能崩溃是每个应用必须面对的现实,既然崩溃已经发生,无法阻挡了,那我们就让它崩也崩得淡定点吧. IOS SDK中提供了一个现成的函数 NSSetUncaughtExce ...
- iOS8 UISearchViewController搜索功能讲解 分类: ios技术 2015-07-14 10:23 76人阅读 评论(0) 收藏
在iOS8以前我们实现搜索功能需要用到UISearchbar和UISearchDisplayController, 在iOS8之后呢, UISearchController配合UITableView的 ...
- 【转】10款GitHub上最火爆的国产开源项目
将开源做到极致,提高效率方便更多用户 接触开源时间虽然比较短但是后续会努力为开源社区贡献自己微薄的力量 衡量一个开源产品好不好,看看产品在 GitHub 的 Star 数量就知道了.由此可见,GitH ...
- js生成随机数
//生成n以内的随机数 function getRandom(n){ return Math.floor(Math.random()*n+1) } //生成1000以内的随机数 alert(getRa ...
- 【转】IntentService的原理及使用
在Android开发中,我们或许会碰到这么一种业务需求,一项任务分成几个子任务,子任务按顺序先后执行,子任务全部执行完后,这项任务才算成功.那么,利用几个子线程顺序执行是可以达到这个目的的,但是每个线 ...
- MongoDB的$type操作符
字段类型定义: db.col.find({"title" : {$type : 2}})
- 《C++ Primer》 chapter 15 TextQuery
<C++ Primer>中第15章为了讲解面向对象编程,举了一个例子:设计一个小程序,能够处理查询给定word在文件中所在行的任务,并且能够处理“非”查询,“或”查询,“与”查询.例如执行 ...
- 【转】java调用存储过程和函数
一.概述 如果想要执行存储过程,我们应该使用 CallableStatement 接口. CallableStatement 接口继承自PreparedStatement 接口.所以CallableS ...