Chinaunix

标题: [C]新手请教x+=y与x=x+y的问题 [打印本页]

作者: ck_lai    时间: 2008-02-20 12:07
标题: [C]新手请教x+=y与x=x+y的问题
书中提到:x+=y比x=x+y少一次运算,不明白为什么,能解释一下吗?
作者: cheng_lai_shun    时间: 2008-02-20 12:37
是的,我不会表达,所以解释不来!呵呵
作者: cugb_cat    时间: 2008-02-20 12:39
稍微有些优化功能的编译器,编译出来的汇编语句应该是一样的。
作者: hemu1190    时间: 2008-02-20 12:51
因为运算符重载的时候,+=是一个运算符;而+和=分别是单独的运算符!
作者: ruoyisiyu    时间: 2008-02-20 13:34
原帖由 cugb_cat 于 2008-2-20 12:39 发表
稍微有些优化功能的编译器,编译出来的汇编语句应该是一样的。

i=0和i=i-i是一个效果
作者: davycu    时间: 2008-02-20 13:42
进来吓了一跳,还以为flw2同学呢,
作者: ck_lai    时间: 2008-02-20 14:50
原帖由 cugb_cat 于 2008-2-20 12:39 发表
稍微有些优化功能的编译器,编译出来的汇编语句应该是一样的。


那效率就一样咯?
作者: cugb_cat    时间: 2008-02-20 15:11
原帖由 ck_lai 于 2008-2-20 14:50 发表


那效率就一样咯?

是,提高效率不应把重点放在这方面,应该是算法的提高。
作者: ck_lai    时间: 2008-02-20 15:27
恩,谢了~~~~
作者: roger0922    时间: 2008-02-20 15:42
原帖由 hemu1190 于 2008-2-20 12:51 发表
因为运算符重载的时候,+=是一个运算符;而+和=分别是单独的运算符!

顶   前者做了一次运算  而后者做了运算后还要赋值于X
作者: flw2    时间: 2008-02-20 15:48
原帖由 davycu 于 2008-2-20 13:42 发表
进来吓了一跳,还以为flw2同学呢,


实在不知道您从哪看出来我们是同学
作者: fl3w    时间: 2008-02-20 16:14
原帖由 flw2 于 2008-2-20 15:48 发表


实在不知道您从哪看出来我们是同学

我们才是
作者: davycu    时间: 2008-02-20 16:43
标题: 回复 #11 flw2 的帖子

作者: flw2    时间: 2008-02-20 16:56
有的系统指令支持把一个数a加到令一个数b并存储在b中,这样编译器可能不需要保存a+b的临时值
在没有这样指令的系统上,比如加法指令为add a,b,a 那么a+=b a=a+b,编译器即使不优化也-更应该-知道使用这个指令,而不是使用临时一个存储或者寄存器
但是我试验了两个系统,gcc对a+=b 和a=a+b都分别产生一样的指令
作者: flw2    时间: 2008-02-20 16:56
原帖由 davycu 于 2008-2-20 16:43 发表

你还这种表情呢?
作者: davycu    时间: 2008-02-20 17:26
标题: 回复 #15 flw2 的帖子
很抱歉无意中的一句话引起您的不快,解释一下我那句话:进来时第一眼看到楼主的头像(现在已经换了)跟阁下的一样,所以说了那句,“同学”只是我平时的习惯用语,不是说你们是同学

占用楼主地方了,还请见谅哈
作者: flw2    时间: 2008-02-20 17:27
原帖由 davycu 于 2008-2-20 17:26 发表
很抱歉无意中的一句话引起您的不快,解释一下我那句话:进来时第一眼看到楼主的头像(现在已经换了)跟阁下的一样,所以说了那句,“同学”只是我平时的习惯用语,不是说你们是同学

占用楼主地方了,还请见谅哈

呵呵,没事,我也没有不愉快,只是这种情况下实在很难理解,你说呢
没事了,不用回
作者: lvziwei    时间: 2008-02-20 22:31
学习中
作者: 林有德    时间: 2008-02-21 00:59
原帖由 hemu1190 于 2008-2-20 12:51 发表
因为运算符重载的时候,+=是一个运算符;而+和=分别是单独的运算符!


是的
作者: blueboy83    时间: 2008-02-21 16:25
这个编译器 难道不会优化吗,哈哈
作者: zx_wing    时间: 2008-02-21 17:11
原帖由 flw2 于 2008-2-20 17:27 发表

呵呵,没事,我也没有不愉快,只是这种情况下实在很难理解,你说呢
没事了,不用回

最近老看你用 这个表情,有啥特别的吗?
作者: flw2    时间: 2008-02-21 17:43
原帖由 zx_wing 于 2008-2-21 17:11 发表

最近老看你用 这个表情,有啥特别的吗?


没什么,跟“晕”差不多
作者: future0906    时间: 2008-02-22 10:51
原帖由 blueboy83 于 2008-2-21 16:25 发表
这个编译器 难道不会优化吗,哈哈

不要将编译器想到万能...........

一些你认为理所当然的优化实际可能并不存在。

所以,我认为,可以的话,尽量写成第一种形式。

虽然只是一条指令的区别,但如果用在核心循环的话,效率就有可能明显了。
作者: whyglinux    时间: 2008-02-23 14:10
原帖由 ck_lai 于 2008-2-20 12:07 发表
书中提到:x+=y比x=x+y少一次运算,不明白为什么,能解释一下吗?


从理论上讲, x=x+y 中对 x 进行两次求值,而在 x+=y 中只进行一次求值。实际上由于编译器的优化,一般这两种形式最终都产生同样的结果,在运行效率上也就没有差别;从而 += 存在的意义是书写简洁,特别是在 x 又是一个复杂表达式的情况下。当然,如果你的编译器不能对此进行优化,两者的效率就有可能有区别了。因此,在程序中应该总是使用前者形式为好。
作者: dxcnjupt    时间: 2008-02-24 15:47
抠语法的话:
x = x+y:
mov eax, [x]
mov ebx, [y]
add eax,ebx
mov [x], eax

x += y:
mov eax, [y]
add [x],  eax

支持cat的观点,c语言不要太在意这种细节的东西。算法和架构才是最重要的
如果碰到核心循环,建议直接用汇编。
汇编语言倒是可以抠一下细节。最近正在测试乱序汇编对流水线性能的优化.......
作者: wuxb45    时间: 2008-02-24 16:55
不一定真的会少。

是否x=x+y就比x+=y多一个指令,还得看编译器如何操作,


楼主可以看看“编译器优化”相关的知识。

x=x+y:

temp<-x+y,
x<-temp.

x+=y;

x<-x+y.

区别就在于是否使用了临时变量
作者: xjtucser    时间: 2008-02-24 17:02
标题: 回复 #1 ck_lai 的帖子
x = x + y; 的处理过程是这样的: 从名字x对应的存储中取出值,从名字y对应的存储中取出值,两个值进行相加,产生一个临时单元,相加的结果首先存放在临时单元中,然后把临时单元的值赋值给x,即写到名字x对应的存储单元中去。

x += y, 直接取出x和y,相加然后把结果更新在x对应的存储单元中,所以少了从中间变量再给x赋值的过程。
作者: wangfanlinlin    时间: 2008-02-24 21:18
拿具体程序看把,有的能体现出少算了一次,因为X+=Y是第2N次的X,而X=X+Y是前面的X是第N+1次的,后面那个才是第N次的
作者: hnynes    时间: 2008-02-25 10:53
对于a = b + c;这一种,系统会先计算加法,并用一个临时的对象将那个和存储一下,然后再将那个临时对象里面的值赋给对象a.

而a += b;没有临时对象这个东西.
作者: soso2008    时间: 2008-02-25 12:01
原帖由 dxcnjupt 于 2008-2-24 15:47 发表
抠语法的话:
x = x+y:
mov eax, [x]
mov ebx, [y]
add eax,ebx
mov [x], eax

x += y:
mov eax, [y]
add [x],  eax

支持cat的观点,c语言不要太在意这种细节的东西。算法和架构才是最重要的
如果 ...



不敢苟同,
我想并不是直接操作内存单元,而是用CPU内部的累加器进行计算,然后再写回内存,
这两种写法,在C编译器层面产生的结果就应该是一样的,
指令运算更不会有差异,
作者: dxcnjupt    时间: 2008-02-25 20:28
原帖由 soso2008 于 2008-2-25 12:01 发表



不敢苟同,
我想并不是直接操作内存单元,而是用CPU内部的累加器进行计算,然后再写回内存,
这两种写法,在C编译器层面产生的结果就应该是一样的,
指令运算更不会有差异,




1有什么理由不允许直接操作内存单元吗??我想不到。

2在不抠语法的情况下,我举双手同意“这两种写法,在C编译器层面产生的结果就应该是一样的,指令运算更不会有差异”,但是我认为都应该优化成直接操作内存。

3刚才在gcc4.1.2上面测了一下,如上一条所说

另外.......直接说eax或者通用寄存器就好了,“CPU内部的累加器”说起来多累啊,又或者你另有所指??
作者: soso2008    时间: 2008-02-26 10:33
要是抠到指令集的层面上,
不同的体系结构可能有差异,但是我还没有见过直接用SDRAM运算加法的,

比如最简单的,在MCS51单片机中,计算加法时,只能用Acc,
用汇编写加法时,
MOV   Acc, X
ADD   Acc, Y
MOV   X, Acc
当然,这个X, Y都是在CPU内部,可以直接访问的,

指令集中没有
ADD   X, Y
这种指令,

我对单片机最熟悉,所以拿单片机来举例子,
其它的体系结构我没研究过,
对于X86系统,具体在L1/L2 cache,和SDRAM之间如何交互等等,我不清楚,
但绝不是一条指令能完成的,

很多细节,我也不清楚,毕竟是搞软件的,对底层处理的细节没有接触过,
不过可以尝试下‘-S’参数,翻译成汇编代码来看,
不过我看不大懂,

int main( void )
{
&nbsp;&nbsp;&nbsp;&nbsp;int x, y;

&nbsp;&nbsp;&nbsp;&nbsp;y = 5;
&nbsp;&nbsp;&nbsp;&nbsp;x = y;

&nbsp;&nbsp;&nbsp;&nbsp;return 0;
}


&nbsp;&nbsp;&nbsp;&nbsp;.file&nbsp;&nbsp;&nbsp;&nbsp;"test1.c"
gcc2_compiled.:
___gnu_compiled_c:
&nbsp;&nbsp;&nbsp;&nbsp;.def&nbsp;&nbsp;&nbsp;&nbsp;___main;&nbsp;&nbsp;&nbsp;&nbsp;.scl&nbsp;&nbsp;&nbsp;&nbsp;2;&nbsp;&nbsp;&nbsp;&nbsp;.type&nbsp;&nbsp;&nbsp;&nbsp;32;&nbsp;&nbsp;&nbsp;&nbsp;.endef
.text
&nbsp;&nbsp;&nbsp;&nbsp;.align 4
.globl _main
&nbsp;&nbsp;&nbsp;&nbsp;.def&nbsp;&nbsp;&nbsp;&nbsp;_main;&nbsp;&nbsp;&nbsp;&nbsp;.scl&nbsp;&nbsp;&nbsp;&nbsp;2;&nbsp;&nbsp;&nbsp;&nbsp;.type&nbsp;&nbsp;&nbsp;&nbsp;32;&nbsp;&nbsp;&nbsp;&nbsp;.endef
_main:
&nbsp;&nbsp;&nbsp;&nbsp;pushl %ebp
&nbsp;&nbsp;&nbsp;&nbsp;movl %esp,%ebp
&nbsp;&nbsp;&nbsp;&nbsp;subl $24,%esp
&nbsp;&nbsp;&nbsp;&nbsp;call ___main
&nbsp;&nbsp;&nbsp;&nbsp;movl $5,-8(%ebp)
&nbsp;&nbsp;&nbsp;&nbsp;movl -8(%ebp),%eax
&nbsp;&nbsp;&nbsp;&nbsp;movl %eax,-4(%ebp)
&nbsp;&nbsp;&nbsp;&nbsp;xorl %eax,%eax
&nbsp;&nbsp;&nbsp;&nbsp;jmp L2
&nbsp;&nbsp;&nbsp;&nbsp;.align 4
L2:
&nbsp;&nbsp;&nbsp;&nbsp;movl %ebp,%esp
&nbsp;&nbsp;&nbsp;&nbsp;popl %ebp
&nbsp;&nbsp;&nbsp;&nbsp;ret


[ 本帖最后由 soso2008 于 2008-2-26 10:39 编辑 ]
作者: soso2008    时间: 2008-02-26 10:48
因为没有证据,很多人让我糊涂,
所以我只能当作想当然。。。
作者: 城市小鸭    时间: 2008-02-26 13:49
原帖由 soso2008 于 2008-2-26 10:33 发表
要是抠到指令集的层面上,
不同的体系结构可能有差异,但是我还没有见过直接用SDRAM运算加法的,

比如最简单的,在MCS51单片机中,计算加法时,只能用Acc,
用汇编写加法时,
MOV   Acc, X
ADD   Acc, Y ...


你说确实混乱,举这个例子想说明什么?  其实 dxcnjupt 已经说得很清楚了
作者: flw2    时间: 2008-02-26 14:47
原帖由 dxcnjupt 于 2008-2-25 20:28 发表




1有什么理由不允许直接操作内存单元吗??我想不到。

2在不抠语法的情况下,我举双手同意“这两种写法,在C编译器层面产生的结果就应该是一样的,指令运算更不会有差异”,但是我认为都应该优化成直 ...

所有的算术逻辑运算都是在ALU中完成的,绝对不会有指令“直接”对存储器加一,即CPU不需要知道存储的值而是直接对存储说:“把它加一”,因为存储器不能接收指令,也不能进行运算
作者: flw2    时间: 2008-02-26 14:51
有些体系结构没有只有存储操作数的指令,有的系统运算绝对不能有存储操作数,但是无论怎么样,运算是在CPU中,不是在存储器中,只是可能被CPU隐藏了,比如x86中的对一个存储字加1
作者: jamesr    时间: 2008-02-26 18:43
提示: 作者被禁止或删除 内容自动屏蔽
作者: 暮云    时间: 2008-02-28 09:42
前者仅是做了一次+=运算,后者先做了+运算,然后又做了赋值,所以前者比后者少了一次运算
作者: 穆哥尔    时间: 2008-02-28 18:45
标题: 回复 #1 ck_lai 的帖子
伙计,你在哪本书中看到的,说出来俺也想看一下
作者: mymtom    时间: 2008-02-28 19:06
原帖由 dxcnjupt 于 2008-2-24 15:47 发表
抠语法的话:
x = x+y:
mov eax, [x]
mov ebx, [y]
add eax,ebx
mov [x], eax

x += y:
mov eax, [y]
add [x],  eax

支持cat的观点,c语言不要太在意这种细节的东西。算法和架构才是最重要的
如果 ...

x = x +y 与 x +=y 生成的指令没有什么区别吧!
好像没有任何区别呀.

  1. int
  2. main(void)
  3. {
  4.         int x, y;

  5.         x = x + y;
  6.         x += y;

  7.         return (0);
  8. }
复制代码

        .file   "xy.c"
        .text
        .p2align 4,,15
.globl main
        .type   main, @function
main:
.LFB2:
        pushq   %rbp
.LCFI0:
        movq    %rsp, %rbp
.LCFI1:
        movl    -8(%rbp), %edx
        leaq    -4(%rbp), %rax
        addl    %edx, (%rax)
        movl    -8(%rbp), %edx
        leaq    -4(%rbp), %rax
        addl    %edx, (%rax)
        movl    $0, %eax
        leave
        ret
.LFE2:
        .size   main, .-main
        .section        .eh_frame,"a",@progbits
.Lframe1:
        .long   .LECIE1-.LSCIE1
.LSCIE1:
        .long   0x0
        .byte   0x1
        .string ""
        .uleb128 0x1
        .sleb128 -8
        .byte   0x10
        .byte   0xc
        .uleb128 0x7
        .uleb128 0x8
        .byte   0x90
        .uleb128 0x1
        .p2align 3
.LECIE1:
.LSFDE1:
        .long   .LEFDE1-.LASFDE1
.LASFDE1:
        .long   .LASFDE1-.Lframe1
        .quad   .LFB2
        .quad   .LFE2-.LFB2
        .byte   0x4
        .long   .LCFI0-.LFB2
        .byte   0xe
        .uleb128 0x10
        .byte   0x86
        .uleb128 0x2
        .byte   0x4
        .long   .LCFI1-.LCFI0
        .byte   0xd
        .uleb128 0x6
        .p2align 3
.LEFDE1:
        .ident  "GCC: (GNU) 3.4.6 [FreeBSD] 20060305"

  1. 编译指令为gcc -O0 -S xy.c
复制代码





欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2