了解汇编级别 ++i 和 i++ 之间的区别

2024-01-03

我知道这个问题的变体已经在这里被问过多次,但我并不是在问两者之间有什么区别。只是想要一些帮助来理解这两种形式背后的组装。

我认为我的问题与whys比到what的差异。

我正在阅读Prata 的 C Primer Plus在处理增量运算符的部分++和使用之间的区别i++ or ++i作者说如果操作符自己使用的话,比如ego++;我们使用哪种形式并不重要。

如果我们看一下以下代码的反汇编(使用 Xcode、Apple LLVM 版本 9.0.0 (clang-900.0.39.2) 编译):

int main(void)
{
    int a = 1, b = 1;

    a++;
    ++b;

    return 0;

}

我们可以看到,实际上使用的形式并不重要,因为两者的汇编代码是相同的(两个变量都会在屏幕上打印出 2)。

初始化a and b:

0x100000f8d <+13>: movl   $0x1, -0x8(%rbp)
0x100000f94 <+20>: movl   $0x1, -0xc(%rbp)

装配用于a++:

0x100000f9b <+27>: movl   -0x8(%rbp), %ecx
0x100000f9e <+30>: addl   $0x1, %ecx
0x100000fa1 <+33>: movl   %ecx, -0x8(%rbp)

装配用于++b:

0x100000fa4 <+36>: movl   -0xc(%rbp), %ecx 
0x100000fa7 <+39>: addl   $0x1, %ecx 
0x100000faa <+42>: movl   %ecx, -0xc(%rbp)

然后作者指出,当运算符及其操作数是较大表达式的一部分时,例如在赋值语句中,使用前缀或后缀确实会产生影响。

例如:

int main(void)
{
    int a = 1, b = 1;
    int c, d;

    c = a++;
    d = ++b;

    return 0;

}

这将打印1 and 2 for c and b, 分别。

And:

初始化a and b:

0x100000f46 <+22>: movl   $0x1, -0x8(%rbp)
0x100000f4d <+29>: movl   $0x1, -0xc(%rbp)

装配用于c = a++; :

0x100000f54 <+36>: movl   -0x8(%rbp), %eax      // eax = a = 1
0x100000f57 <+39>: movl   %eax, %ecx            // ecx = 1
0x100000f59 <+41>: addl   $0x1, %ecx            // ecx = 2
0x100000f5c <+44>: movl   %ecx, -0x8(%rbp)      // a = 2
0x100000f5f <+47>: movl   %eax, -0x10(%rbp)     // c = eax = 1

装配用于d = ++b; :

0x100000f62 <+50>: movl   -0xc(%rbp), %eax      // eax = b = 1
0x100000f65 <+53>: addl   $0x1, %eax            // eax = 2
0x100000f68 <+56>: movl   %eax, -0xc(%rbp)      // b = eax = 2
0x100000f6b <+59>: movl   %eax, -0x14(%rbp)     // d = eax = 2

显然,分配的汇编代码是不同的:

  • 表格c = a++;包括寄存器的使用eax and ecx。它用ecx用于执行增量a by 1,但使用eax为作业。

  • 表格d = ++b; uses ecx对于两者的增量b by 1和作业。

我的问题是:

  • 这是为什么?
  • 是什么决定了c = a++;需要两个寄存器而不是只有一个(ecx例如)?

在以下声明中:

a++;
++b;

表达式的求值都不a++ and ++b用来。这里编译器实际上只对这些运算符的副作用感兴趣(即:将操作数增加一)。在这种情况下,两个运算符的行为方式相同。因此,这些语句产生相同的汇编代码也就不足为奇了。

然而,在以下声明中:

c = a++;
d = ++b;

表达式的评估a++ and ++b与编译器相关,因为它们必须存储在c and d, 分别:

  • d = ++b;: b递增,并且该递增的结果分配给d.
  • c = a++;: 的价值a首先被分配给c进而a是递增的。

因此,这些运算符在这种情况下的行为有所不同。因此,在不启用更积极的优化的情况下,至少在开始时产生不同的汇编代码是有意义的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

了解汇编级别 ++i 和 i++ 之间的区别 的相关文章

随机推荐