- 浏览: 667938 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (297)
- J2SE (78)
- swt/飞信 (20)
- mysql/mssql (17)
- 设计模式 (5)
- windows (18)
- 闲言碎语 (19)
- struts 1.x (6)
- JVM (6)
- tomcat/jetty (8)
- jquery/javascript (15)
- web前端 (6)
- J2EE (0)
- PHP (6)
- 算法设计 (17)
- 数据结构 (3)
- C/C++ (6)
- linux (19)
- 程序打包 (8)
- eclipse/myeclipse (10)
- 其他杂项 (13)
- 应聘 (9)
- spring/spring mvc (4)
- Maven/Ant (2)
- ERROR (1)
- nosql/hbase (1)
- hibernate (3)
- Solr/Lucene (1)
最新评论
-
乔木1937:
太感谢了,看到你的文章终于解决这个问题了!
[转载]通过端口 1433 连接到主机 localhost 的 TCP/IP 连接失败。错误:“Connection refused: connect。 -
xianweisi:
竟然还有马
精简JRE - 实例Swing计算器 with 精简JRE(续) -
Javkburd:
我刚也遇到这个问题,然后也把默认端口改成了1433,只差最后没 ...
[转载]通过端口 1433 连接到主机 localhost 的 TCP/IP 连接失败。错误:“Connection refused: connect。 -
yeshaoting:
kingbinchow 写道 最近的爪哇岛 没有什么货进项呀 ...
jQuery方法区别(四)click() bind() live() delegate()区别 -
kingbinchow:
最近的爪哇岛 没有什么货进项呀!
jQuery方法区别(四)click() bind() live() delegate()区别
[不同编译器]函数参数求值顺序分析(附前置与后置++执行效率)
函数参数的求值顺序
函数参数的求值顺序跟不同语言编译器的处理方式有关,有些语言编译器从左向右处理,而有时从右往左处理.
这种编译器求值顺序的不同会相应地产生不同的输出结果.
测试程序:
向测试方法method(int a,int b)中传入类似于++x,x+y,x++的实参.
e.g. method(++x,x+y),method(x+y,++x),...
根据输出结果的不同推出参数求值顺序.
一. C语言编译环境
---------------------------------------前绪分析---------------------------------------
前置++程序:
// 前置++程序 // author: jarg // http://jarg.iteye.com/ #include "stdio.h" void main() { int x = 2; printf("%d",++x); printf("%d",x); }
该C语言程序反汇编后的指令:
10: int x = 2;
00401028 mov dword ptr [ebp-4],2
11: printf("%d",++x);
0040102F mov eax,dword ptr [ebp-4]
00401032 add eax,1
00401035 mov dword ptr [ebp-4],eax
00401038 mov ecx,dword ptr [ebp-4]
0040103B push ecx
0040103C push offset string "%d" (00422fa4)
00401041 call printf (00401090)
00401046 add esp,8
12: printf("%d",x);
00401049 mov edx,dword ptr [ebp-4]
0040104C push edx
0040104D push offset string "%d" (00422fa4)
00401052 call printf (00401090)
00401057 add esp,8
13: }
汇编指令解释:
第十条语句: int x = 2;对应汇编信息是mov dword ptr [ebp-4],2(dword ptr [ebp-4]是变量x的存储单元,语句是将值2放到变量x的存储单元中).
第十一条语句(总共8条指令):
0040102F~00401038: 变量x存储单元中的数值存入ax寄存器,然后ax寄存器中数值加1,再将ax寄存器中的数值存入变量x的存储单元,最后将变量x的存储单元中的数值存入cx寄存器中(总共4条指令)
0040103B: 将cx寄存器中的数值压入栈,作为函数的第二个实参值
0040103C: 将字符串"%d"压入栈,作为函数第一个实参值
00401041: 调用printf函数,执行函数过程
后置++程序:
// 后置++程序 // author: jarg // http://jarg.iteye.com/ #include "stdio.h" void main() { int x = 2; printf("%d",x++); printf("%d",x); }
该C语言程序反汇编后的指令:
10: int x = 2;
00401028 mov dword ptr [ebp-4],2
11: printf("%d",x++);
0040102F mov eax,dword ptr [ebp-4]
00401032 mov dword ptr [ebp-8],eax
00401035 mov ecx,dword ptr [ebp-8]
00401038 push ecx
00401039 push offset string "%d" (00422fa4)
0040103E mov edx,dword ptr [ebp-4]
00401041 add edx,1
00401044 mov dword ptr [ebp-4],edx
00401047 call printf (00401090)
0040104C add esp,8
12: printf("%d",x);
0040104F mov eax,dword ptr [ebp-4]
00401052 push eax
00401053 push offset string "%d" (00422fa4)
00401058 call printf (00401090)
0040105D add esp,8
13: }
汇编指令解释:
第十条语句: int x = 2;对应汇编信息是mov dword ptr [ebp-4],2(dword ptr [ebp-4]是变量x的存储单元,语句是将值2放到变量x的存储单元中).
第十一条语句(总共10条指令):
0040102F~00401035: 变量x存储单元中的数值存入ax寄存器,再将ax寄存器中的数值存入变量x的存储单元的下一个存储单元,最后将变量x的存储单元的下一个存储单元中的数值存入cx寄存器中(总共3条指令)
00401038: 将cx寄存器中的数值压入栈,作为函数的第二个实参值
0040103C: 将字符串"%d"压入栈,作为函数第一个实参值
0040103E~00401044: 将变量x的存储单元中的数值存入dx寄存器,再将dx寄存器中的数值加1,最后最dx寄存器中的数值存入变量x的存储单元中
00401047: 调用printf函数,执行函数过程
结论(C语言编译环境下):
① 前置++与后置++程序不同就在于一个是++x,另一个是x++;
这一区别造成了执行过程相差2条指令.
由此可见,++x的执行效率高于x++.另外,前置++先执行x=x+1,然后将x值压入栈,做为函数实参值,调用函数;而后置++先将x值压入栈,做为函数实参值,然后执行x=x+1,再调用函数.
② 二个程序的printf函数的都是先处理第二个实参,压入栈;然后处理第一个实参,压入栈.
由此可见,C语言编译环境下函数求值顺序是从右向左.
栈是一个先入后出的数据结构,最后一个实参先入栈,则会最后一个出栈,这样在函数从左向右顺序依次读取形参的时候,做出栈操作给对应的形参赋值.
---------------------------------------前绪分析---------------------------------------
C语言测试程序:
// 函数参数的求值顺序 // author: jarg // http://jarg.iteye.com/ #include "stdio.h" void main() { int x = 2; printf("%d\t%d\t%d",x,++x,x++); printf("\t%d\n",x); }
由前绪分析的结论②已经得出: C语言编译环境下函数求值顺序是从右向左
初始化时x = 2,求值顺序是从右向左,则输出为3 3 2 4
输出结果:
3 3 2 4
二. Java语言编译环境
Java语言测试程序:
// 函数参数的求值顺序 // author: jarg // http://jarg.iteye.com/ public class Test { public static void main(String[] args) { int x = 2; System.out.print("" + (x) + "\t" + (++x) + "\t" + (x++)); System.out.print("\t" + x); } }
初始化时x = 2,假设:
① 假设求值顺序是从左向右,则输出为2 3 3 4
② 假设求值顺序是从右向左,则输出为3 3 2 4
输出结果:
2 3 3 4
结论(Java语言编译环境下):
① 由此可知,Java编译环境对函数求值顺序是按照函数参数声明顺序(符合我们正常思维逻辑)的从左向右.
解释:
虚拟机为每一个调用的Java(非本地)方法建立一个新的栈帧.栈帧包括:为方法的局部变量所预留的空间,该方法的操作数栈,以及特定虚拟机实现需要的其他所有的信息.局部变量和操作数栈大小在编译时计算出来,并设置到class文件中去,然后虚拟机就能够了解到方法的栈帧需要多少内存.当虚拟机调用一个方法的时候,它为该方法创建恰当大小的栈帆,再将新的栈帧压入Java栈.
值得一提的Java编译器将Java方法的参数严格按照它们的声明顺序放到"局部变量数组"中.
处理方法时,虚拟机从所调用帧内的操作数栈中弹出实参值.虚拟机把对应的值存入局部变量数组参数对应位置,这种存入可以随机存入.
而C语言需要将后面参数得先入栈(先入后出结构),然后需要参数值的时候出栈供方法使用.
这种不同导致编译器求值顺序的差异.
② 同C语言编译环境下前置后置++执行过程类似,在Java编译环境函数从左向右顺序求值情况下,++x在执行完x=x+1操作后才做传值操作,这就导致后面的x++中的x值变成3;表达式的输出结果也是3,不难看出x++是先做传值操作再完成的x=x+1操作,这一情况体现在下一条语句:System.out.print("\t" + x);中,x输出的是4.
但是由于本人能力不够,不知道如何查看Java程序编译后类似于C语言汇编后的指令代码.因此,对于Java语言中二者执行效率孰高孰低不敢妄自定夺.姑且类推猜测前置++效率高于后置++.
本人才疏学浅,汇编描述以及Java编译环境结论①解释的地方有不准确的地方,望海涵.
发表评论
-
Java - Convert String to enum
2012-11-17 22:03 1857http://stackoverflow.com/que ... -
[ERROR]Premature end of file
2012-09-28 11:41 3218[ERROR]Premature end of file ... -
测试java.util.Map.Entry
2012-07-18 16:13 980/** * Copyright (c) 201 ... -
关于eclipse启动出错问题的解决办法
2012-06-09 09:31 1401转自:http://blog.csdn.net/jkpt ... -
Myeclipse中把java代码导成UML类图
2012-05-18 14:53 2315MyEclipse 中选择window,在 Open ... -
[转载]java synchronized详解
2012-05-15 17:18 818http://www.cnblogs.com ... -
[转载]Java 根据 HashMap 的 value 进行排序
2012-05-08 09:58 904转载:http://www.oschina.net/co ... -
JAVA实时屏幕监控
2012-04-29 16:13 3249JAVA实时屏幕监控 说明: 本程序会运 ... -
[JAVA实时屏幕监控]JAVA使用Internet代理设置
2012-04-29 14:50 1331JAVA使用Internet代理设置 描述:首先 ... -
[JAVA实时屏幕监控]JAVA通过注册表获取Internet代理设置
2012-04-29 14:47 2291JAVA通过注册表获取Internet代理设置 ... -
[JAVA实时屏幕监控]JAVA发送邮件
2012-04-29 14:28 2433JAVA发送邮件 描述:利用commons-em ... -
[JAVA实时屏幕监控]JAVA屏幕截图
2012-04-29 14:19 1263JAVA屏幕截图 /** * 产生截图 ... -
[JAVA实时屏幕监控]Java使用代理服务器
2012-04-24 13:36 2412/** * Copyright (c) 2012 T ... -
java.util.ConcurrentModificationException解决办法
2012-04-23 10:47 1526java.util.ConcurrentModi ... -
[转载]java.util.ConcurrentModificationException
2012-04-23 09:20 926java.util.ConcurrentModif ... -
整数转换成字节型数组
2012-04-22 13:16 5967整数转换成字节型数组 描述: 整数(in ... -
java.lang.NoClassDefFoundError: javax/mail/Message解决方法
2012-04-18 10:33 1203缺少activation.jar 和 mail.jar ... -
设置javax.swing.JFrame窗口外观
2012-03-29 15:34 0设置javax.swing.JFrame窗口外 ... -
设置javax.swing.JFrame窗口外观
2012-03-29 15:34 0设置javax.swing.JFrame窗口 ... -
Java图形界面外观包substance.jar
2012-03-29 15:33 0一直以来都认为用Swing做出来的程序 ...
相关推荐
MPLAB C18 C 编译器 函数库,内有中文说明
内含词法分析、LL(1)方法语法分析分析简单语句(如:i+i*i)、LR(0)和SLR(1)方法进行语法分析、四元式生成、汇编代码生成。 内包含部分LL(1)文法和一个SLR(1)文法。 编译原理课程设计报告(小型编译器)。
很小很实用的一款C++编译器,有函数速查手册在里面!!好好的收藏!
对C++编译器区分重载函数无任何意义的信息是 A.参数类型B.参数个数.docx
瑞萨CS+编译器资料
小型编译器包含词法分析和语法分析,还有预测分析表
C plus+编译系统+基于C++的小型c编译器的设计与实现+本科毕业设计+课设+c语言+源码 C plus+编译系统+基于C++的小型c编译器的设计与实现+本科毕业设计+课设+c语言+源码 C plus+编译系统+基于C++的小型c编译器的设计...
是一个针对于编译器的代码分析,分析的编译器有两款,分别是Pascal—S和C0的编译器。
1.根据题目要求,经过自己的分析,我在实现解释器的程序中,将总体过程分为4个阶段,分别为Scanner(词法分析)、Paerser(语法分析)、Semantic(语义分析)、Main(绘制图形与窗口建立),全过程采用JAVA语言、递归下降子...
表达式求值顺序自右向左 无优先级区别 可添加括号 不支持数组 不支持全局变量 ... 目录结构 src 源码 |- analyser 语义分析与中间代码生成 |- compiler 编译总控程序与界面 |- error 错误类 |- interpreter 解释程序...
华中科技大学 编译原理 面向过程的C语言的编译器设计 功能包括:词法分析和语法分析、语义分析、中间代码生成的 源码 题目:c--语言编译器设计与实现(请为自己的编译器命名) 源语言定义:或采用教材中Decaf语言,...
Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言
编译器中的语法词法分析器(源代码),对初学编译器的兄弟们很有用!
flex builder 编译器参数 就是点工程属性里的option里填的
编译器中c语言 词法分析器 编译器中c语言 词法分析器 编译器中c语言 词法分析器 编译器中c语言 词法分析器 编译器中c语言 词法分析器 编译器中c语言 词法分析器
编译器参数 详解
08_29_C++ C++编译器对普通成员函数的内部处理08_29_C++ C++编译器对普通成员函数的内部处理08_29_C++ C++编译器对普通成员函数的内部处理08_29_C++ C++编译器对普通成员函数的内部处理08_29_C++ C++编译器对普通...
这个是PIC单片机的C32编译器用户指南和编译器函数手册的中文版,很不错,免费送给大家!
编译原理课程设计源码 词法分析,编译器,有可执行代码
编译原理课上用到的函数绘图语言的编译器,用java写的