示例:
a : ++i;
b : i++;
c : i += 1;
d : i = i + 1;
假设每个abcd被完全同时调用,其中一个将首先被执行?
答案 0 :(得分:9)
使用gcc 5.2编译该程序:
#include<stdio.h>
int main()
{
int i = 0;
++i;
i++;
i += 1;
i = i + 1;
return 0;
}
它给出了这个ASM:
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 0
add DWORD PTR [rbp-4], 1 #++i
add DWORD PTR [rbp-4], 1 #i++
add DWORD PTR [rbp-4], 1 #i += 1
add DWORD PTR [rbp-4], 1 #i = i + 1
mov eax, 0
pop rbp
ret
这意味着与gcc 5.2 它的执行速度完全相同。
从4.4.7到5.2的版本似乎是一样的。
答案 1 :(得分:5)
在这个特定的例子中,所有四个表达式都具有完全相同的外部可观察结果,因此一个称职的编译器应该为它们生成完全相同的代码。
编译器不会盲目地读取代码并为每个语句生成一些指令,编译器会根据标准推断出代码的结果,并生成整个程序根据需要运行所需的代码。因此,询问关于单个陈述的表现问题几乎总是毫无意义。让我举个例子:
void foo(unsigned int a, unsigned int b) { unsigned int i = a * b; }
void bar(unsigned int a, unsigned int b) { unsigned int i = a + b; }
哪一个更快?功能foo
或bar
?很多人会说“当然乘法速度较慢”,但很可能答案是:两者都同样快,因为非常简单的死存储优化会发现没有使用i
,所以不需要计算它,所以编译器可以将功能优化为零。我们来试试吧:
$ cat > foo.c
void foo(unsigned int a, unsigned int b) { unsigned int i = a * b; }
void bar(unsigned int a, unsigned int b) { unsigned int i = a + b; }
$ cc -S -fomit-frame-pointer -O2 foo.c
$ cat foo.s
[... I edited out irrelevant spam to make this more readable ...]
_foo: ## @foo
retq
_bar: ## @bar
retq
两个函数中唯一的指令是retq
,它只是从函数返回。
答案 2 :(得分:1)
现代编译器足够聪明,可以优化所有这四种情况以提高性能。
您应该注意,在最后一个表达式i = i+1
中,i
将被评估两次。
答案 3 :(得分:0)
在编程中,一元运算符的优先级高于其他运算符。一元运算符在执行其他运算符之前执行。前后增量运算符是一元运算符的例子,而c和d是二元运算符,因此后面执行。也就是c只是d的简写符号,因此两者都需要相同的时间,而a和b,a是在b之前执行,因为后增量比预增量快。 我希望这个答案有所帮助。