- 注册时间
- 2006-6-19
- 最后登录
- 2010-1-23
⑥精研
- 积分
- 2223
|
发表于 2008-6-12 06:34:24
|
显示全部楼层
引用第8楼nightaway于2008-03-12 21:33发表的 :
a+=1 编译后的汇编指令 add
a++ 编译后的汇编指令 inc
inc 的运算周期 小于 add 所以 a++ 比 a+=1 快
如果楼主有疑问可以学学汇编语言.. 这样你的编码水平会大增.. 引用第12楼jiangcq于2008-05-26 10:32发表的 :
回答正确,+= 比 = + 效率要高很多,特别是在早期的计算机上
####################
a=a+1
MOV EAX,A
MOV EBX,1
ADD EAX,EBX
MOV A,EAX
##################
a+=1
MOV EAX,A
INC EAX
MOV A,EAX
####################
如果没记错的话应该是这样计算的 这个……事情要具体问题具体分析对吧,张冠李戴就不太好了 ^ ^
更详细的论述发在这里了:http://rednaxelafx.javaeye.com/blog/202334
+=之类的复合赋值运算符在许多语言都有,语义类似但是实现的方式并不总相同。
RGSS里的脚本语言是Ruby,RPG Maker VX里使用的Ruby是1.8.1版的MRI。Ruby源代码并没有被直接编译到机器码,而是被Ruby解释器所解释:先把源代码翻译成抽象语法树,然后解释抽象语法树。
在Ruby里,一切皆是对象。因此像是加号减号之类的运算,也被看作是对象上的方法。a += 1的语义是a = a.+(1)(语义是:调用a对象上的+()方法,把1作为参数传进去,然后将方法的返回值赋值给a)。
+=的语义不是单独定义,而是由+()方法所决定的;换句话说一个类定义了+()方法就自动具备了+=。假如有语句a = 1,那么a是一个Fixnum,+=当中调用的+()方法就是Fixnum#+()。
先看看+=被解析器识别为什么了。Ruby的扫描器(词法分析器)里有这么一段:- case '+':
- c = nextc();
- if (lex_state == EXPR_FNAME || lex_state == EXPR_DOT) {
- lex_state = EXPR_ARG;
- if (c == '@') {
- return tUPLUS;
- }
- pushback(c);
- return '+';
- }
- if (c == '=') {
- yylval.id = '+'; // 注意这里,id是'+'
- lex_state = EXPR_BEG;
- return tOP_ASGN; // 然后整体以tOP_ASGN返回
- }
复制代码 可以看到+=被识别为tOP_ASGN类型的token。
a += 1形式的语句对应的这条语法:- statement: //...
- | var_lhs tOP_ASGN command_call
- // ...
- | //...
- ;
复制代码 语法对应着解析器,而解析器会生成抽象语法树。如果等号前的是||则语法生成NODE_OP_ASGN_OR节点,如果是&&则生成NODE_OP_ASGN_AND节点,其它则调用call_op()函数生成NODE_CALL节点。- var_lhs tOP_ASGN command_call
- {
- value_expr($3);
- if ($1) {
- ID vid = $1->nd_vid;
- if ($2 == tOROP) {
- $1->nd_value = $3;
- $$ = NEW_OP_ASGN_OR(gettable(vid), $1);
- if (is_asgn_or_id(vid)) {
- $$->nd_aid = vid;
- }
- }
- else if ($2 == tANDOP) {
- $1->nd_value = $3;
- $$ = NEW_OP_ASGN_AND(gettable(vid), $1);
- }
- else {
- $$ = $1; // 获得var_lhs对应的节点
- $$->nd_value = call_op(gettable(vid),$2,1,$3); // 这里,call_op将返回一个NODE_CALL节点,
- // 并赋值给var_lhs对应节点的“值”
- }
- }
- else {
- $$ = 0;
- }
- }
复制代码 由于节点的“值”(nd_value)被赋值为一个NODE_CALL节点,这里实质上完成了将a += 1变为a = a.+(1)的转换。
看看a = a + 1对应的语法和动作:- lhs '=' command_call
- {
- $$ = node_assign($1, $3);
- }
复制代码 结合下面node_assign()函数的实现,可以看到这里是把右手边的节点赋值给了左手边节点的“值”(nd_value)。并且,右手边的a + 1对应的语法与动作如下:- arg '+' arg
- {
- $$ = call_op($1, '+', 1, $3);
- }
复制代码 也是调用call_op()生成NODE_CALL节点,跟前面a += 1时一样。
于是,a += 1与a = a + 1在被解析后所生成的语法树是一样的,后续执行中就都是等价的了。
- static NODE*
- node_assign(lhs, rhs)
- NODE *lhs, *rhs;
- {
- if (!lhs) return 0;
- value_expr(rhs);
- switch (nd_type(lhs)) {
- case NODE_GASGN:
- case NODE_IASGN:
- case NODE_LASGN:
- case NODE_DASGN:
- case NODE_DASGN_CURR:
- case NODE_MASGN:
- case NODE_CDECL:
- case NODE_CVDECL:
- case NODE_CVASGN:
- lhs->nd_value = rhs; // 注意这里
- break;
- case NODE_ATTRASGN:
- case NODE_CALL:
- lhs->nd_args = arg_add(lhs->nd_args, rhs);
- break;
- default:
- /* should not happen */
- break;
- }
- return lhs;
- }
复制代码
这是Fixnum#+()对应的C函数:- /*
- * call-seq:
- * fix + numeric => numeric_result
- *
- * Performs addition: the class of the resulting object depends on
- * the class of <code>numeric</code> and on the magnitude of the
- * result.
- */
- static VALUE
- fix_plus(x, y)
- VALUE x, y;
- {
- if (FIXNUM_P(y)) {
- long a, b, c;
- VALUE r;
- a = FIX2LONG(x);
- b = FIX2LONG(y);
- c = a + b;
- r = LONG2NUM(c);
- return r;
- }
- if (TYPE(y) == T_FLOAT) {
- return rb_float_new((double)FIX2LONG(x) + RFLOAT(y)->value);
- }
- return rb_num_coerce_bin(x, y);
- }
复制代码 该函数被注册到Ruby的类型系统中:- rb_define_method(rb_cFixnum, "+", fix_plus, 1);
复制代码 rb_cFixnum是继承自rb_cInteger的类:- rb_cFixnum = rb_define_class("Fixnum", rb_cInteger);
复制代码 上面rb_define_method函数使得fix_plus与一个NODE_CFUNC关联在了一起。这个函数会调用rb_intern(name)来将方法名转换为ID,这里对运算符做了特殊处理:- if (name[0] != '_' && ISASCII(name[0]) && !ISALNUM(name[0])) {
- /* operators */
- int i;
- for (i=0; op_tbl[i].token; i++) {
- if (*op_tbl[i].name == *name &&
- strcmp(op_tbl[i].name, name) == 0) {
- id = op_tbl[i].token;
- goto id_regist;
- }
- }
- }
复制代码 这个特殊处理可以保证运算符与内建函数的对应关系。 |
|