了解汇编级别 ++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++ 之间的区别 的相关文章

  • 用 C++ 进行服装建模 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在编写一些软件 最终会绘制一个人体框架 可以配置各种参数 并且计划是在假人身上放置某种衣服 我研究
  • VB.NET 相当于 C# 属性简写吗?

    是否有与 C 等效的 VB NET public string FirstName get set 我知道你能做到 Public Property name As String Get Return name ToString End Ge
  • Unix网络编程澄清

    我正在翻阅这本经典书籍Unix网络编程 https rads stackoverflow com amzn click com 0139498761 当我偶然发现这个程序时 第 6 8 节 第 179 180 页 include unp h
  • 启动时出现 OData v4 错误:找不到段“Whatever”的资源

    我正在构建新的 v4 服务 一切进展顺利 直到我为新模型 实体添加了新控制器 并在启动站点进行测试运行时收到此错误 控制器似乎编码正确 就像其他控制器一样 控制器 CustomersOData 中的操作 GetFeed 上的路径模板 Cus
  • 如何将 #ifdef DEBUG 添加到 Xcode?

    我的项目中有一些代码永远不应该在发布版本中使用 但在测试时很有用 我想做这样的事情 ifdef DEBUG Run my debugging only code endif 在 Xcode 4 中哪里添加 DEBUG 设置 我尝试将其放入
  • 在新的浏览器进程中打开 URL

    我需要在新的浏览器进程中打开 URL 当浏览器进程退出时我需要收到通知 我当前使用的代码如下 Process browser new Process browser EnableRaisingEvents true browser Star
  • 将 System.Windows.Input.KeyEventArgs 键转换为 char

    我需要将事件参数作为char 但是当我尝试转换 Key 枚举时 我得到的字母和符号与传入的字母和符号完全不同 如何正确地将密钥转换为字符 这是我尝试过的 ObserveKeyStroke this new ObervableKeyStrok
  • 如何在 C# 中定义文本框数组?

    您好 当我在 Windows 申请表上创建文本框时 我无法将其命名为 box 0 box 1 等 我这样做的目的是因为我想循环使用它们 其实我发现TextBox array firstTextBox secondTextBox 也有效
  • ASP.NET:获取自 1970 年 1 月 1 日以来的毫秒数

    我有一个 ASP NET VB NET 日期 我试图获取自 1970 年 1 月 1 日以来的毫秒数 我尝试在 MSDN 中寻找方法 但找不到任何东西 有谁知道如何做到这一点 从 NET 4 6 开始 该方法ToUnixTimeMillis
  • 单击 form2 上的按钮触发 form 1 中的方法

    我对 Windows 窗体很陌生 我想知道是否可以通过单击表单 2 中的按钮来触发表单 1 中的方法 我的表格 1 有一个组合框 我的 Form 2 有一个 保存 按钮 我想要实现的是 当用户单击表单 2 中的 保存 时 我需要检查表单 1
  • 使用 JNI 从 Java 代码中检索 String 值的内存泄漏

    我使用 GetStringUTFChars 从使用 JNI 的 java 代码中检索字符串的值 并使用 ReleaseStringUTFChars 释放该字符串 当代码在 JRE 1 4 上运行时 不会出现内存泄漏 但如果相同的代码在 JR
  • 在一个字节中存储 4 个不同的值

    我有一个任务要做 但我不知道从哪里开始 我不期待也绝对不想要代码中的答案 我想要一些关于该怎么做的指导 因为我感到有点失落 将变量打包和解包到一个字节中 您需要在一个字节中存储 4 个不同的值 这些值为 NAME RANGE BITS en
  • ESP 和 EBP 寄存器是什么?

    我发现ESP寄存器是当前堆栈指针 EBP是当前堆栈帧的基指针 但是 我不理解这些定义 我刚刚开始学习如何在汇编程序中编码 What I understand is that ESP points towards the stack itse
  • 如何使用 watin 中的 FileUploadDialogHandler 访问文件上传对话框

    我正在使用 IE8 和 watin 并尝试通过我的网页测试上传文件 我不能简单地使用 set 方法设置上传文件 例如 ie FileUpload Find ById someId Set C Desktop image jpg 因为上传文本
  • Visual Studio 中的测试单独成功,但一组失败

    当我在 Visual Studio 中单独运行测试时 它们都顺利通过 然而 当我同时运行所有这些时 有些通过 有些失败 我尝试在每个测试方法之间暂停 1 秒 但没有成功 有任何想法吗 在此先感谢您的帮助 你们可能有一些共享数据 检查正在使用
  • 如何将自定义 JSON 文件添加到 IConfiguration 中?

    我正在使用 asp net Autofac 我正在尝试加载自定义 JSON 配置文件 并基于该文件创建 实例化 IConfiguration 实例 或者至少将我的文件包含到默认情况下构建的 IConfiguration asp net 中
  • 如何编写一个同时需要请求和响应Dtos的ServiceStack插件

    我需要提供本地化数据服务 所有本地化的响应 Dto 都共享相同的属性 IE 我定义了一个接口 ILocalizedDto 来标记那些 Dto 在请求端 有一个ILocalizedRequest对于需要本地化的请求 Using IPlugin
  • 有人可以提供一个使用 Amazon Web Services 的 itemsearch 的 C# 示例吗

    我正在尝试使用 Amazon Web Services 查询艺术家和标题信息并接收回专辑封面 使用 C 我找不到任何与此接近的示例 所有在线示例都已过时 并且不适用于 AWS 的较新版本 有一个开源项目CodePlex http www c
  • 如何从main方法调用业务对象类?

    我已将代码分为业务对象 访问层 如下所示 void Main Business object public class ExpenseBO public void MakeExpense ExpensePayload payload var
  • 当另一个线程可能设置共享布尔标志(最多一次)时,是否可以读取共享布尔标志而不锁定它?

    我希望我的线程能够更优雅地关闭 因此我尝试实现一个简单的信号机制 我不认为我想要一个完全事件驱动的线程 所以我有一个工作人员有一种方法可以使用关键部分优雅地停止它Monitor 相当于C lock我相信 绘图线程 h class Drawi

随机推荐