在 K&R 第 1 章中:
该语句
++nc
提供了一个新的运算符 ,++
表示加一。您可以改为编写nc = nc + 1
,但++nc
更简洁且通常更高效。
什么时候预增量比替代方案更有效?至少对于大多数事情来说,两者的汇编都是add
(edit: or inc
) 指令。它们何时不同?
在 K&R 第 1 章中:
该语句
++nc
提供了一个新的运算符 ,++
表示加一。您可以改为编写nc = nc + 1
,但++nc
更简洁且通常更高效。
什么时候预增量比替代方案更有效?至少对于大多数事情来说,两者的汇编都是add
(edit: or inc
) 指令。它们何时不同?
该文本早已过时。在 70 年代,编译器可能会为 ++n 产生更有效的输出,但现在可能是这样。所有现代编译器都会产生相同的代码。
至少对于大多数事情来说,两者的程序集都是 add 指令。
这并不完全正确:通常有一个单独的“递增”指令。但是,这无关紧要,因为任何半体面的编译器都会为++nc
and生成相同的机器代码nc = nc + 1
。
换句话说,没有性能差异。这本书写的时候可能有编译器不是很好的时候,但现在已经没有了。
我不确定,我只是在大声思考(也许我不应该):也许在 K&R 的时代,++nc
被编译成比nc = nc + 1
(例如,增量指令,而不是加法)更有效的东西。然而,如今,编译器可能会自动优化这一点。
这是我可以看到的gcc -S <filename>
。我会让你得到你想要的!
>
> cat 1.c
#include <stdio.h>
int main()
{
int i=0;
++i;
return 0;
}
>
> cat 2.c
#include <stdio.h>
int main()
{
int i=0;
i++;
return 0;
}
>
> cat 3.c
#include <stdio.h>
int main(void)
{
int i=0;
i = i + 1;
return 0;
}
>
> gcc -S 1.c 2.c 3.c
>
>
> diff 1.s 2.s
1c1
< .file "1.c"
---
> .file "2.c"
>
> diff 2.s 3.s
1c1
< .file "2.c"
---
> .file "3.c"
>
> diff 3.s 1.s
1c1
< .file "3.c"
---
> .file "1.c"
>
>
以下是.s
文件的内容,1.c
与 2.s 和 3.s 相比,说明相同!
> cat 1.s
.file "1.c"
.text
.globl main
.type main, @function
main:
.LFB2:
pushq %rbp
.LCFI0:
movq %rsp, %rbp
.LCFI1:
movl $0, -4(%rbp)
addl $1, -4(%rbp)
movl $0, %eax
leave
ret
.LFE2:
.size main, .-main
.section .eh_frame,"a",@progbits
.Lframe1:
.long .LECIE1-.LSCIE1
.LSCIE1:
.long 0x0
.byte 0x1
.string "zR"
.uleb128 0x1
.sleb128 -8
.byte 0x10
.uleb128 0x1
.byte 0x3
.byte 0xc
.uleb128 0x7
.uleb128 0x8
.byte 0x90
.uleb128 0x1
.align 8
.LECIE1:
.LSFDE1:
.long .LEFDE1-.LASFDE1
.LASFDE1:
.long .LASFDE1-.Lframe1
.long .LFB2
.long .LFE2-.LFB2
.uleb128 0x0
.byte 0x4
.long .LCFI0-.LFB2
.byte 0xe
.uleb128 0x10
.byte 0x86
.uleb128 0x2
.byte 0x4
.long .LCFI1-.LCFI0
.byte 0xd
.uleb128 0x6
.align 8
.LEFDE1:
.ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-48)"
.section .note.GNU-stack,"",@progbits
>
对于“正常”变量,应该没有其他答案所暗示的区别。只有合格,结果可能会有所不同nc
。voloatile
对于这样的变量,+1
表单必须nc
首先计算加载的表达式,nc
然后执行加法。对于++
表单,编译器仍然可以采取捷径并在适当的位置增加变量。