n/=10与n=n/10的区别

3

n/=10n=n/10在执行速度方面有区别吗?

就像n----n的执行速度不同一样...


除了编译之外,它们之间没有任何区别。 - nabroyan
3
n/=10 理论上不创建临时变量,而 n=n/10 理论上会创建一个临时变量,但实际上编译器会进行优化。 - Roger Rowland
13
如有疑问,可以让编译器创建两种变体的汇编清单并进行比较。 - Andreas Fester
3
实际上,n/=10 和 n=n/10 之间的执行速度差异(几乎可以确定)与 --n 和 n-- 之间的差异相同。 - William Pursell
@WilliamPursell 我猜现代编译器在两个序列点之间生成n--和--n相同的汇编代码?所以n/=10和n=n/10也应该如此? - Koushik Shetty
显示剩余3条评论
4个回答

5

不,实际上并没有:

[C99: 6.5.16.2/3]: 形如 E1 op= E2 的复合赋值表达式与简单赋值表达式 E1 = E1 op (E2) 的区别仅在于只计算一次左值 E1

因此,这只会对具有副作用的非平凡表达式(例如函数调用)产生影响。

否则,我想理论上会涉及一个中间临时变量,但你必须非常不幸才能在编译后的可执行文件中保留这样的临时变量。你不会看到两种方法之间的任何性能差异。

通过基准测试和比较生成的汇编代码来验证这一点。


1
除非 nvolatile,否则可能的优化将被抑制。 - Alexey Frunze
1
@AlexeyFrunze:我不明白为什么。标准保证了复合操作的行为,如上所述。 - Lightness Races in Orbit
在C11中,这段文字被修改以表明对于复合运算符,无法在计算n / 10和将结果赋值回n之间发生具有不确定序列的函数调用;并且还定义了原子操作的行为。 - M.M

2

给定以下C代码:

int f1(int n) {
   n /= 10;
   return n;
}

int f2(int n) {
   n = n / 10;
   return n;
}

使用gcc -O4编译的结果基本上是这样的:

f1:
        movl    %edi, %eax
        movl    $1717986919, %edx
        sarl    $31, %edi
        imull   %edx
        sarl    $2, %edx
        subl    %edi, %edx
        movl    %edx, %eax
        ret

f2:
        movl    %edi, %eax
        movl    $1717986919, %edx
        sarl    $31, %edi
        imull   %edx
        sarl    $2, %edx
        subl    %edi, %edx
        movl    %edx, %eax
        ret

我已省略了一些实际上是清单部分的样板文件。

在这种情况下,两种选择没有区别。

根据使用的编译器,指令执行的实际环境以及编译器优化级别,生成的代码可能会有所不同。但您始终可以使用此方法来检查生成的机器代码是否不同。


尝试使用以下代码:int f1(int nn) { volatile int n = nn; n /= 10; return n; }int f1(int nn) { volatile int n = nn; n = n / 10; return n; }。这可能会有所不同。 - Alexey Frunze
不,它添加了一些movl指令,但在这两种情况下仍然是相同的;-) - Andreas Fester

0

它们之间没有区别。


-2

我已经在KEIL交叉编译器中检查了这两个表达式,并且需要相同的执行时间:

=================================================
     5: x=x/5; 
     6:  
C:0x0005    EF       **MOV      A,R7**

C:0x0006    75F005   **MOV      B(0xF0),#0x05**

C:0x0009    84       **DIV      AB**

     7: x/=5; 

C:0x000A    75F005   **MOV      B(0xF0),#0x05**

C:0x000D    84       **DIV      AB**

C:0x000E    FF       **MOV      R7,A**

================================================

所以,就像 --nn-- 一样,没有任何区别。


2
有无限多种可能的C语言实现和无限多个包含此源代码的C程序。在一个C语言实现上测试程序只能告诉你关于一个C语言实现和一个程序的信息。相比之下,C语言的规则告诉你关于所有C语言实现的信息。除非问题明确限制在单一情况下,否则不能通过单一测试来回答问题。 - Eric Postpischil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接