xiaofanyy 10月10日 平静 的说 我的生活没颜色了。晕了。迷茫了。   小鱼游 10月10日 悲伤 的说 额,突然觉得人生失去了方向~~~~~   fay_meng 10月9日 平静 的说 冒泡下,提高知名度...   zdk6105 10月9日 平静 的说 哈哈,何为缘?聚散皆为缘   一堆泪水 10月9日 郁闷 的说 期待有缘人。。。   小鱼游 10月8日 平静 的说 干了一整天的活,好累哟   水木落 10月8日 平静 的说 9日8点40分,离校后第一次掠过杨凌。。。。。。   逍遥散人 10月6日 平静 的说 终于回杨凌了 心情还是那样没变化 闷了   荦荦夕颜 10月6日 平静 的说 武汉归来 带给大家一首好听的歌 擦肩而过   知多少 10月6日 平静 的说 输入要叽歪的内容_   [查看全部 328 条唧唧歪歪...]


打印

看到一篇 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