丰之痛 大约3小时前 高兴 的说 今天又想去打篮球了!!!!   丰之痛 12月2日 郁闷 的说 机电那伙人太火了..........   看海的日子 12月2日 平静 的说 输入要叽歪的内容_   穿拖鞋的兔子 12月1日 平静 的说 翘课   沙漠★寂寞 11月30日 平静 的说 机电那伙人又开始分钱了,刚刚又赚了很,见者有份,速度去抢!!!   一千年胡杨 11月30日 平静 的说 我爱你   穿拖鞋的兔子 11月30日 平静 的说 鼻子冻的红红的,不想上校内   鲍豪斯 11月30日 平静 的说 机电那伙正在分钱..要的都去看要吧!!!   小鱼游 11月30日 悲伤 的说 俺消失咧将近一整天,都米有个人想我   zdk6105 11月30日 无聊 的说 风好大,期待一场雪:天好冷,渴望一场爱   [查看全部 451 条唧唧歪歪...]


打印

看到一篇 i++, ++i 这类的文章觉的有意思就贴上来了

看到一篇 i++, ++i 这类的文章觉的有意思就贴上来了

复制内容到剪贴板
代码:
C语言中,只包含一个表达式的语句,如
x = (i++) * 2;
称为“表达式语句”。表达式语句结尾的";"是C标准定义的顺序点之一,但这不等同于说所有的";"都是顺序点,也不是说顺序点只有这一种。下面就是标准中定义的顺序点:

函数调用时,实参表内全部参数求值结束,函数的第一条指令执行之前(注意参数分隔符“,”不是顺序点);
&&操作符的左操作数结尾处;
||操作符的左操作数结尾处;
?:操作符的第一个操作数的结尾处;
逗号运算符;
表达式求值的结束点,具体包括下列几类:自动对象的初值计算结束处;表达式语句末尾的分号处;do/while/if/switch/for语句的控制条件的右括号处;for语句控制条件中的两个分号处;return语句返回值计算结束(末尾的分号)处。

定义顺序点是为了尽量消除编译器解释表达式时的歧义,如果顺序点还是不能解决某些歧义,那么标准允许编译器的实现自由选择解释方式。理解顺序点还是要从定义它的目的来下手。

再举一个例子:
y = x++, x+1;
已知这个语句执行前x=2,问y的值是多少?
逗号运算符是顺序点。那么该表达式的值就是确定的,是4,因为按照顺序点的定义,在对x+1求值前,顺序点","前的表达式——x++求值的全部副作用都已发生完毕,计算x+1时x=3。这个例子中顺序点成功地消除了歧义。
注意这个歧义是怎样消除的。因为中间的顺序点使“相邻顺序点间对象的值只更改一次”的条件得到满足。

y = (x++) * (x++), 执行前x=2, y=?
答案是,因为这个表达式本身不包含顺序点,顺序点未能消除歧义,编译器生成的代码使y取4, 6(以及更多的一些可能值)都是符合标准定义的,程序员自己应为这个不符合顺序点定义的表达式造成的后果负责。
http://blog.csdn.net/thisisll/ http://spaces.msn.com/thisisll/

TOP

目前追究这个对我没什么意义好像。

TOP

有些东西是需要积累的
http://blog.csdn.net/thisisll/ http://spaces.msn.com/thisisll/

TOP

不是积累的问题,而是意义不大

TOP

应该避这种写法

TOP

for(int i=0;i<20;i++)
for(int i=0;i<20;++i)
是什么区别??
雅易软件
www.yayisoft.com
laiqinyi#at#gmail.com
QQ群34803490
招聘java,net,js程序员

TOP

尽量都用++i,以避免不必要的复制开销!

TOP

引用:
引用第6楼laoyangzi2006-10-31 13:31发表的:
尽量都用++i,以避免不必要的复制开销!
这个不一定,我刚刚在dev-C++,版本是4.9.9.2作了个小试验
代码:
#include <iostream>
using namespace std;
int main() {
   int i = 0, j = 0;
   i++;
   ++j;
    }
反汇编得到<Main>:
...
0x4012ba <main+42>: movl $0x0,0xfffffffc (%ebp)  //i = 0;
.................................: movl $0x0,0xfffffff8 (%ebp)  //j = 0;
.................................: lea   0xfffffffc(%ebp),%eax  // 得到i的地址并放到eax里面
.................................: incl  (%eax)                // "i = i+1",(%eax)表示i
.................................: lea   0xfffffff8(%ebp),%eax  // 得到j的地址并放到eax里面
.................................: incl  (%eax)                // "j = j+1",(%eax)表示j
.................................: mov $0x0,%eax             //清零
.................................: leave                        //释放堆栈
.................................: ret                          //返回,退出<main>

PS:这只是个汇编片段,省了无关的代码:)
由此,可见,至少在gcc上面,i++和++i没有什么区别

TOP

这要看编译器的问题了
这种简单的可以优化
但你没试一些复杂语句中看能优化吗>?
http://blog.csdn.net/thisisll/ http://spaces.msn.com/thisisll/

TOP

我偷懒了,直接dump过来了:)
$ gcc -g test.c -o test   --可以看见没有作任何优化

YETIboy@~
$ gdb test
GNU gdb 2003-09-20-cvs (cygwin-special)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i686-pc-cygwin"...
(gdb) disass main
Dump of assembler code for function main:
0x00401050 <main+0>:   push  %ebp
0x00401051 <main+1>:   mov   %esp,%ebp
0x00401053 <main+3>:   sub   $0x18,%esp
0x00401056 <main+6>:   and   $0xfffffff0,%esp
0x00401059 <main+9>:   mov   $0x0,%eax
0x0040105e <main+14>:  mov   %eax,0xfffffff0(%ebp)
0x00401061 <main+17>:  mov   0xfffffff0(%ebp),%eax
0x00401064 <main+20>:  call  0x4013e0 <_alloca>
0x00401069 <main+25>:  call  0x401470 <__main>
******下面关于for (i = 0; i < 300; i++);**********************
0x0040106e <main+30>:  movl  $0x0,0xfffffffc(%ebp) --"i = 0"
0x00401075 <main+37>:  cmpl  $0x12b,0xfffffffc(%ebp)-- 判断是否i < 300
0x0040107c <main+44>:  jle   0x401080 <main+48> 如果<为真,跳到<main+48>
0x0040107e <main+46>:  jmp   0x401087 <main+55>
0x00401080 <main+48>:  lea   0xfffffffc(%ebp),%eax--把i地址放入eax中
0x00401083 <main+51>:  incl  (%eax)--“i++”
0x00401085 <main+53>:  jmp   0x401075 <main+37> 跳回,形成"i"的循环
************ for (j = 0; j < 300; ++j);**********************
0x00401087 <main+55>:  movl  $0x0,0xfffffff8(%ebp) --"j = 0;
0x0040108e <main+62>:  cmpl  $0x12b,0xfffffff8(%ebp) --j < 300?
0x00401095 <main+69>:  jle   0x401099 <main+73>  
0x00401097 <main+71>:  jmp   0x4010a0 <main+80>
0x00401099 <main+73>:  lea   0xfffffff8(%ebp),%eax
0x0040109c <main+76>:  incl  (%eax) (++j)!!!!!!!!和 i++一样的指令:)            
0x0040109e <main+78>:  jmp   0x40108e <main+62> --形成"j"循环
---Type <return> to continue, or q <return> to quit---
******以下4句关于k = i++*************************
0x004010a0 <main+80>:  mov   0xfffffffc(%ebp),%eax 把i的值放到eax中
0x004010a3 <main+83>:  mov   %eax,0xfffffff4(%ebp) 再把eax中的值放到k中
0x004010a6 <main+86>:  lea   0xfffffffc(%ebp),%eax再一次把i放到eax中(本来就是i的地址)
0x004010a9 <main+89>:  incl  (%eax) i++ (如果gcc是人的话,就不用多此一举了)
*******以下4句关于k = ++j*************************
0x004010ab <main+91>:  lea   0xfffffff8(%ebp),%eax  
0x004010ae <main+94>:  incl  (%eax) ---"++j"
0x004010b0 <main+96>:  mov   0xfffffff8(%ebp),%eax
0x004010b3 <main+99>:  mov   %eax,0xfffffff4(%ebp)
***********************************************
不管是k = i++ 或者 k = ++j都是用了4条指令,也只是指令的次序不一样
***********************************************
0x004010b6 <main+102>:  leave
0x004010b7 <main+103>:  ret
End of assembler dump.
(gdb) l                     ;这里为原程序
1     main() {
2          int i,j,k;
3          for (i = 0; i < 300; i++);
4          for (j = 0; j < 300; ++j );
5          k = i++;
6          k = ++j;
7     }

TOP

$ cc -g test.c -o test 无优化

YETIboy@~
$ gdb test
GNU gdb 2003-09-20-cvs (cygwin-special)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Publ
welcome to change it and/or distribute copies of it u
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show
This GDB was configured as "i686-pc-cygwin"...
(gdb) disass main
Dump of assembler code for function main:
0x00401050 <main+0>:   push  %ebp
0x00401051 <main+1>:   mov   %esp,%ebp
0x00401053 <main+3>:   sub   $0x18,%esp
0x00401056 <main+6>:   and   $0xfffffff0,%esp
0x00401059 <main+9>:   mov   $0x0,%eax
0x0040105e <main+14>:  mov   %eax,0xfffffff4(%ebp)
0x00401061 <main+17>:  mov   0xfffffff4(%ebp),%eax
0x00401064 <main+20>:  call  0x4013b0 <_alloca>
0x00401069 <main+25>:  call  0x401440 <__main>
0x0040106e <main+30>:  movl  $0x0,0xfffffffc(%ebp)
0x00401075 <main+37>:  movl  $0x0,0xfffffff8(%ebp)
0x0040107c <main+44>:  lea   0xfffffffc(%ebp),%eax
0x0040107f <main+47>:  addl  $0x3e8,(%eax)   i += 1000;
0x00401085 <main+53>:  lea   0xfffffff8(%ebp),%eax
0x00401088 <main+56>:  addl  $0x3e8,(%eax)  j = j  + 1000;
0x0040108e <main+62>:  leave
0x0040108f <main+63>:  ret
End of assembler dump.
(gdb) l
1     main() {
2          int i = 0, j = 0;
3          i += 1000;
4          j = j + 1000;
5     }
(gdb)
由此可见,在gcc中,i += 1与i = i + 1是等效的:)
再看看最强的优化是什么样子,还是这个程序
$ cc -g test.c -o test -O3-----O1,O2,O3优化3个等级,O3最高

YETIboy@ ~
$ ./test
i:1000,j:1000  验证结果,怕优化错误,呵呵,看来多余了
YETIboy@ ~
$ gdb test
GNU gdb 2003-09-20-cvs (cygwin-special)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License
welcome to change it and/or distribute copies of it under certa
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty"
This GDB was configured as "i686-pc-cygwin"...
(gdb) disass main
Dump of assembler code for function main:
0x00401060 <main+0>:   push  %ebp
0x00401061 <main+1>:   xor   %eax,%eax
0x00401063 <main+3>:   mov   %esp,%ebp
0x00401065 <main+5>:   sub   $0x18,%esp
0x00401068 <main+8>:   and   $0xfffffff0,%esp
**前面都省了很多步骤,上面主要分配局部变量和堆栈指针对齐能被16整除的地址(这样提高
寻址速度)***********************************************************
0x0040106b <main+11>:  call  0x4013c0 <_alloca>
0x00401070 <main+16>:  call  0x401450 <__main>
0x00401075 <main+21>:  movl  $0x3e8,0x8(%esp,1)!!!!直接赋值到变量地址!!!
0x0040107d <main+29>:  movl  $0x3e8,0x4(%esp,1)且用的是esp,堆栈指针!!
0x00401085 <main+37>:  movl  $0x401050,(%esp,1)
0x0040108c <main+44>:  call  0x401460 <printf> !!
0x00401091 <main+49>:  mov   %ebp,%esp
0x00401093 <main+51>:  pop   %ebp
0x00401094 <main+52>:  ret
***可以看见,类似于int i = 0的语句其实都不存在了*****************
*******下面是调用printf,可以看见,这是一个c library runtime,(应该和CLR还是有很大差别),也就是在连接时才确定地址的,gcc没有编译它,只负责连接****************************
运行时候才连接
End of assembler dump.
(gdb) disass printf
Dump of assembler code for function printf:
0x00401460 <printf+0>:  jmp   *0x4040a4
0x00401466 <printf+6>:  nop
0x00401467 <printf+7>:  nop
0x00401468 <printf+8>:  add   %al,(%eax)
0x0040146a <printf+10>: add   %al,(%eax)
0x0040146c <printf+12>: add   %al,(%eax)
0x0040146e <printf+14>: add   %al,(%eax) ;这个看不懂:(
End of assembler dump.
**下面是源程序*****************************************
(gdb) l
1     #include <stdlib.h>
2     main() {
3          int i = 0, j = 0;
4          i += 1000;
5          j = j + 1000;
6          printf("i:%d,j:%d",i,j);
7     }
(gdb)
连这么简单的程序都这么多优化,可想而知,编译器是多么的强大:)

TOP