自增/减运算符,前缀++i与后缀i++的区别

最近在用 for 循环的时候,发现了自增运算符几种不同的写法,有点好奇,就想复习回顾下。

1 自增/减运算符

1.1 初始印象

首先捋一下运算符在前后的差别,脑子中第一印象是这个

  • ++i,先加,再用
  • i++,先用,再加

1.2 深入剖析

除此之外,还有什么区别呢?我尝试在汇编代码中找一下区别,看下机器语言的执行过程

1.2.1 i++ 汇编实现

i++ 的测试代码如下

int fortest()
{int i = 0;return i++;
}
fortest():push    rbpmov     rbp, rspmov     DWORD PTR [rbp-4], 0    ; 初始化int变量mov     eax, DWORD PTR [rbp-4]  ; 先使用变量i的值,拷贝一次lea     edx, [rax+1]            ; 原变量值做一次自增操作mov     DWORD PTR [rbp-4], edx	; 将自增后的edx再拷贝给初始int变量pop     rbpret

参考 ChatGPT 回答如下:

  1. push rbp: 将当前函数的基址指针(Base Pointer,BP)压入栈中,为当前函数的栈帧(Stack Frame)做准备。
  2. mov rbp, rsp: 将栈指针(Stack Pointer,SP)的值赋给基址指针,建立当前函数的栈帧。
  3. mov DWORD PTR [rbp-4], 0: 将值0存储到基址指针减4的内存位置,即在栈帧中分配一个4字节的空间,并将其初始化为0。
  4. mov eax, DWORD PTR [rbp-4]: 将栈帧中存储的值加载到寄存器eax中。
  5. lea edx, [rax+1]: 将寄存器eax中的值加1,并将结果存储到寄存器edx中。这里使用的是地址计算指令(LEA,Load Effective Address),实际上不会执行真正的加法操作,而是将地址计算的结果存储到目标寄存器中。
  6. mov DWORD PTR [rbp-4], edx: 将寄存器edx中的值存储到栈帧中原先存储值0的位置,相当于将原先的值加1。
  7. pop rbp: 函数结束时,恢复调用函数前的基址指针。
  8. ret: 返回,结束当前函数的执行。

1.2.2 ++i 汇编实现

同样的作为对比,看一下 ++i 的汇编代码

int fortestV2()
{int i = 0;return ++i;
}

对应汇编语言代码如下

fortestV2():push    rbpmov     rbp, rspmov     DWORD PTR [rbp-4], 0    ; 初始化add     DWORD PTR [rbp-4], 1    ; 变量自增mov     eax, DWORD PTR [rbp-4]  ; 返回自增后的临时变量pop     rbpret

1.3 小结

在此之中发现了一点猫腻,可以看到后缀 i++ 运算符,多了一次拷贝操作。从机器语言的执行过程来看,多了一步操作,就会多一点耗时。

另外,与其他朋友交流的过程中,提到了现代编译器是否会对此代码做优化,暂未有结论,咨询 ChatGPT 结果看起来也是通用的,目前还没具体了解到会对类似代码做优化,记录一下,后续如果学习到了,再作补充完善。

附上 ChatGPT 回答:
现代编译器通常会进行优化,以尽可能地消除 i++++i 的性能差异。这种优化可能包括:

  1. 寄存器分配: 编译器可能会将循环中的计数器 i 分配到一个寄存器中,这样无论是前置递增还是后置递增,都可以在寄存器中执行,而不必每次都访问内存。

  2. 循环展开: 编译器可能会将循环展开为一系列简单的操作,以减少递增操作的次数。在这种情况下,i++++i 的性能差异可能会被进一步减小。

  3. 代码重排: 编译器可能会重新排列代码以利用处理器的流水线和缓存。这可能会导致 i++++i 的性能差异变得不那么明显。

总的来说,现代编译器会尽量优化代码,以提高性能并减少不必要的性能差异。因此,开发者通常不需要太过担心 i++++i 的性能问题,除非在非常性能敏感的场景下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/816489.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于物理原理的p-GaN HEMT动态导通电阻SPICE建模

来源:Physics-Based SPICE Modeling of Dynamic ON-State Resistance of p-GaN HEMTs(TPEL 23年) 摘要 这封快报介绍了一种新型基于物理学原理的SPICE建模方法,专门针对氮化镓基p型门极高电子迁移率晶体管(p-GaN HEM…

【学习笔记十五】批次管理和容量管理

一、批次管理 1.配置 SAP EWM 特定参数 激活仓库的批次管理 2.ERP端物料需要启用批次管理 3.EWM物料需要启用批次管理 一般是ERP启用批次管理,相关的配置也会传输到EWM系统 4.建立批次主数据 5.创建采购订单并创建内向交货单,维护批次 6.维护产品主数…

【VS2019】x64 Native Tools Command Prompt for Vs 2019使用conda命令进入环境

【VS2019】x64 Native Tools Command Prompt for Vs 2019使用conda命令进入环境 安装完VS2019后,打开终端x64 Native Tools Command Prompt for Vs 2019,直接运行conda会出现‘conda’ 不是内部或外部命令,也不是可运行的程序 原因分析&am…

免费GPT-3.5部署指南

OpenAI近期宣布,GPT-3.5现已支持无账号使用,这一变化无疑为全球AI爱好者带来了福音。然而,由于网络和地域限制,国内许多朋友仍然面临着使用上的挑战。 今天,我将向大家推荐两个开源项目,它们能够帮助您在国…

Lua脚本使用手册(Redis篇)

Lua脚本 **简介:**Lua是一种功能强大的,高效,轻量级,可嵌入的脚本语言。它是动态类型语言,通过使用基于寄存器的虚拟机解释字节码运行,并具有增量垃圾收集的自动内存管理,是配置,脚…

26、Lua 学习笔记之四(Lua中的基本函数库)

Lua中的基本函数库 assert(v[,mess age])collectgarbage (opt [, arg])dofile (filename)error (message [, level])_G全局环境表(全局变量)getfenv(f)getmetatable(object)ipairs (t)load (func [, chunkname])loadfile ([filename])loadstring (string [, chunkname])next (t…

electron自动更新版本,复制可用

1、安装electron-updater要保证这3个安装在package.json - devDependencies里面,否则打包会缺少模块 2、其他报错有可能 electron版本和electron-updater 版本不兼容,兼容情况查询官网 3、setFeedURL() 服务器地址目录 例如&#…

MySQL详细使用

1.安装 官网下载地址:MySQL :: Download MySQL Community Server (Archived Versions) 2.配置 添加环境变量 验证是否添加成功 cmd管理员身份打开,输入mysql(如下为成功) 初始化MySQL 以管理员身份运行cmd 输入 mysqld --ini…

React搭建一个文章后台管理系统

1、项目准备 本篇文章讲解的是一个简单的文章后台管理系统,系统的功能很简单,如下:登录、退出;首页;内容(文章)管理:文章列表、发布文章、修改文章。 1)React官方脚手架:create-rea…

安装IntelliJ IDEA插件教程

安装IntelliJ IDEA插件:一份详细指南 在提升IntelliJ IDEA开发效率的过程中,插件扮演着不可或缺的角色。它们为IDE提供了额外的功能和工具,以满足开发者在特定编程语言、框架、测试、版本控制等方面的个性化需求。本文将为您详细阐述如何在I…

【已开源】​基于stm32f103的爬墙小车

​基于stm32f103的遥控器无线控制爬墙小车,实现功能为可平衡在竖直墙面上,并进行移动和转向,具有超声波防撞功能。 直接上: 演示视频如:哔哩哔哩】 https://b23.tv/BzVTymO 项目说明: 在这个项目中&…

数模 线性规划模型理论与实践

线性规划模型理论与实践 1.1 线性规划问题 在人们的生产实践中,经常会遇到如何利用现有资源来安排生产,以取得最大经济效益的问题。此类问题构成了运筹学的一个重要分支一数学规划,而线性规划(Linear Programming 简记LP)则是数学规划的一个…

架构师系列-搜索引擎ElasticSearch(五)- 索引设计

索引创建后,要非常谨慎,创建不好后面会出现各种问题。 索引设计的重要性 索引创建后,索引分片只能通过_split和_shrink 接口对其进行成倍的增加和缩减。 ES的数据是通过_routing分配到各个分片上的,所以本质上不推荐区改变索引的…

ubuntu git相关操作

1 安装git sudo apt install git git --version git version 2.25.1 2 解决git超时 2.1 扩大post的buffer git config --global http.postBuffer 524288000 git config --global http.postBuffer 157286400 2.2 换回HTTP1上传。上传之后再切换回HTTP2 …

AI克隆语音(基于GPT-SoVITS)

概述 使用GPT-SoVITS训练声音模型,实现文本转语音功能。可以模拟出语气,语速。如果数据质量足够高,可以达到非常相似的结果。相比于So-VITS-SVC需要的显卡配置更低,数据集更小(我的笔记本NVIDIA GeForce RTX 4050 Lap…

智能水务系统:构建高效节水的城市水网

随着城市化进程的加速和人民生活水平的提高,对水务管理的需求也越来越高。传统的水务管理方式已经无法满足现代社会的需求,而智能水务系统的出现为水务管理带来了新的变革。本文将从项目背景、需求分析、建设目标、建设内容、技术方案、安全设计等方面&a…

网络篇06 | 应用层 自定义协议

网络篇06 | 应用层 自定义协议 01 固定协议设计(简化版)1)总体设计2)值设计 02 可变协议设计(进阶版)1)固定头(Fixed Header)2)可变头(Variable H…

UBuntu18.04通过ODBC连接MySQL远程数据库

今天在做一个Qt视频播放器的小项目然后想要在ubuntu18.04运行这个项目,需要在Qt中连接远程的MySQL数据库,所以用到了ODBC。我在连接时遇到了一些问题,加之网上的教程各说纷纭,所以我花了很多时间去解决,所以决定做做笔…

数据资产与数据要素的重要性及数据资产入表的实践指南

## 引言在当今快速发展的数字化时代,数据资产已经成为企业最宝贵的资源之一。数据资产不仅对企业的运营决策有着至关重要的影响,而且在企业的财务健康和市场竞争力方面扮演着核心角色。数据要素,作为构成数据资产的基本单元,其管理…

【CSS】CSS水平居中方案

CSS水平居中方案 1. 行内元素水平居中 设置父元素的text-align:center .box {width: 300px;height: 300px;margin: 100px auto;text-align: center;background-color: pink; }2. 块级元素水平居中 当块级元素设置了明确的宽度数值时,可以使用margin: 0 auto 3.…