IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 关于i++和++i在for中的执行效率问题 -> 正文阅读

[C++知识库]关于i++和++i在for中的执行效率问题

引言:有位朋友问了一下为什么在for循环中一般i的自增使用 ++i 而不是 i++ ,下列是本次关于这个问题引发的一系列讨论。如有错误欢迎指正。

1 为什么选择++i

众所周知,由于i++需要在自增前先保存旧值,所以cpu在执行i++时需要先保存i的旧值在一个临时存储空间,然后再对i进自增操作。而++i不需要保存旧值,直接对i进行自增后将自增后的值进行返回。
由此可知,i++在自增时会多一步保存旧值的操作,这导致了运行效率会比++i稍低。
但在现代编译器中,对c++代码进行编译的时候当发现i++的返回值并没有被使用时,编译器会把i++优化成++i。所以如果使用的是c++11以后的标准的话,写成++ii++都是可以的,就看个人习惯了。
不过在查找资料的过程中我看到了一句话:(出自Quora)

Compiler optimization may save you, but may not be always the case.
编译器优化并不总是能按照你理想的方式去帮助你。

共勉。

2 对于i++和++i的一些测试

对于上述的理论,很自然的验证想法有两个思路,第一个思路是反编译程序后获得汇编代码,然后看在编译器级别是如何进行了代码优化;第二个思路是拿数据进行实际测试。当然由于本人看不懂汇编代码,ida反编译出来的代码顺序我也不是很懂,所以进行实际测试。由于测试存在一定的偶然性和系统误差,如果测出不同的结果欢迎在评论区指正。

2.1 在现代编译器中测试

测试环境:

c++标准:c++11
IDE:Clion(学生优惠)
操作系统:Windows10
CPU:i5-7200U

测试思路:

下面会列举出五个测试函数
第一个测试for循环中++i的执行时间
第二个测试for循环中i++的执行时间
第三个,由于编译器优化方式是检测到i++的返回值并没有被使用,所以将i++优化成了++i,那么我们主动的去使用i++的返回值,这样可以做到阻止编译器优化。所以第三个测试的是阻止编译器优化的i++执行。
第四个作为第三个的对照组,因为第三个测试中多了一步赋值操作,所以在第四个测试中测试多了赋值操作的++i执行时间。
第五个测试for循环中i=i+1的执行时间。

测试规模:

for循环执行3000000000次(即30亿次)
使用long long 类型进行测试

测试代码:

#include <iostream>
#include "bits/stdc++.h"
#include<windows.h>
#include <ctime>
#define MAX 3000000000

void testAddBeforeI();
void testAddAfterI();
void testTemp();
void testTemp2();
void test3();

int main(){
    testAddBeforeI();
    testAddAfterI();
    testTemp();
    testTemp2();
    test3();
    return 0;
}

void testAddBeforeI(){
    std::cout << "++i" << std::endl;

    long start_time = GetTickCount();

    for(long long i= 0; i < MAX; ++i){
    }
    long end_time = GetTickCount();

    std::cout<< "花费时间:"<< end_time - start_time << std::endl;
}

void testAddAfterI(){
    std::cout << "i++" << std::endl;

    long long temp;

    long start_time = GetTickCount();
    for(long long i= 0; i < MAX;i++){
    }
    long end_time = GetTickCount();

    std::cout<< "花费时间:"<< end_time - start_time << std::endl;
}
// 阻止编译器优化
void testTemp(){
    std::cout << "temp = i++" << std::endl;
    long long temp;


    long start_time = GetTickCount();
    for(long long i= 0; i < MAX; temp = i++){
    }
    long end_time = GetTickCount();

    std::cout<< "花费时间:"<< end_time - start_time << std::endl;

}

void testTemp2(){
    std::cout << "temp = ++i" << std::endl;
    long long temp;
    long start_time = GetTickCount();

    for(long long i= 0; i < MAX; temp = ++i){
    }
    long end_time = GetTickCount();

    std::cout<< "花费时间:"<< end_time - start_time << std::endl;

}

void test3(){
    std::cout << "i +=i" << std::endl;
    long start_time = GetTickCount();

    for(long long i= 0; i < MAX; i += 1){
    }
    long end_time = GetTickCount();

    std::cout<< "花费时间:"<< end_time - start_time << std::endl;

}

测试结果:
在这里插入图片描述

从图片中可以清晰的看到++i 和 i++ 的执行时间差距不大。i +=1则花费时间稍多。但我个人感觉在误差范围内可以认为三者的执行效率接近。
而temp= i++的情况则稍微比i++执行时间稍长,这在预测范围之内。
但让我不理解的是为什么temp= ++i的执行时间比其他的方式执行效率低得多?经过多次测试基本上可以确定这确实在无法范围以外了。这个问题我无法解决,如果有人能解答我不胜感激。

2.2新的问题

上面的代码是执行了空的for循环进行测试,但笔者在测试的使用尝试将 i 进行累加求和的时候发现了新的问题。

测试环境同2.1
测试思路

将原本的空for换成sum += i 进行累加求和运算。

测试代码:

#include <iostream>
#include "bits/stdc++.h"
#include<windows.h>
#include <ctime>
#define MAX 3000000000

void testAddBeforeI();
void testAddAfterI();
void testTemp();
void testTemp2();
void test3();

int main(){
    testAddBeforeI();
    testAddAfterI();
    testTemp();
    testTemp2();
    test3();
    return 0;
}

void testAddBeforeI(){
    std::cout << "++i" << std::endl;
    long long sum = 0;

    long start_time = GetTickCount();

    for(long long i= 0; i < MAX; ++i){
        sum += i;
    }
    long end_time = GetTickCount();

    std::cout<< "花费时间:"<< end_time - start_time << std::endl;
    std::cout << "求和"<< sum <<std::endl;
}

void testAddAfterI(){
    std::cout << "i++" << std::endl;

    long long sum = 0;

    long start_time = GetTickCount();
    for(long long i= 0; i < MAX;i++){
        sum += i;
    }
    long end_time = GetTickCount();

    std::cout<< "花费时间:"<< end_time - start_time << std::endl;
    std::cout << "求和"<< sum <<std::endl;
}

void testTemp(){
    std::cout << "temp = i++" << std::endl;
    long long temp;
    long long sum = 0;

    long start_time = GetTickCount();
    for(long long i= 0; i < MAX; temp = i++){
        sum += i;
    }
    long end_time = GetTickCount();

    std::cout<< "花费时间:"<< end_time - start_time << std::endl;
    std::cout << "求和"<< sum <<std::endl;
}

void testTemp2(){
    std::cout << "temp = ++i" << std::endl;
    long long temp;
    long long sum = 0;
    long start_time = GetTickCount();

    for(long long i= 0; i < MAX; temp = ++i){
        sum += i;
    }
    long end_time = GetTickCount();

    std::cout<< "花费时间:"<< end_time - start_time << std::endl;
    std::cout << "求和"<< sum <<std::endl;
}

void test3(){
    std::cout << "i +=i" << std::endl;
    long start_time = GetTickCount();
    long long sum = 0;
    for(long long i= 0; i < MAX; i += 1){
        sum += i;
    }
    long end_time = GetTickCount();

    std::cout<< "花费时间:"<< end_time - start_time << std::endl;
    std::cout << "求和"<< sum <<std::endl;
}

测试结果:
测试结果

可以从图中看出首先所有求和都是正确的。
其次能明显发现第一组、第二组、第四组和第五组的执行时间几乎没有区别,但令人疑惑的是第三组测试数据却比其他组数据快了非常多。这令我非常不解,也无法给出一个合理的猜想。如果有人能解释,本人不尽感激。

3 总结

在此次for循环中i++++i的执行效率的探索中我学会了很多新的知识,在解决问题的过程中我也在不断提出新的猜想,然后重复验证。虽然我也没有办法解决所有的问题,这证明了我的知识储备还远远不够。
学习新的知识是令人激动和快乐的,和朋友的不断讨论、逐步逼近答案的过程也令人热血沸腾。欢迎指正和友善的讨论。
感谢流浪工作室的@刘奇翰提出的问题。在和他讨论的过程中也让我认识到了许多不足和欠缺的知识。
不断进步。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-07 11:51:13  更:2021-12-07 11:52:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:33:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码