分享

顿悟,神秘的register关键字(C语言篇)

 西北望msm66g9f 2020-03-29

1、唠唠嗑(听说文章与音乐更配)

    今天文章开头为大家挑选一首非常经典的歌曲,估计喜爱《仙剑》的小伙伴听到这个音乐脑海中又会闪现一幕幕画面,大伙可以感受一下!今天手把手为大家解析一个C语言关键字register,可能这个关键字大家在平时的项目开发中用得并不是很多,大部分都是在书籍文档中了解到,估计部分小伙伴根本就没有敲过该关键字。哈哈,作者在之前的文章中一直提到一个'存在即合理'的观点。这也是我一直保持着生活学习中满满好奇心的指导思想。好了不啰嗦了,来进入今天的主题,作者将通过实验现象帮助大家理解和分析该关键字:

2、register基础介绍

    register字面上的意思是寄存器的意思,C语言中用该关键字进行修饰表示该变量频繁的被使用,比如局部变量定义:register int Var = 0;,并且建议将该变量放到寄存器中运行,以提高速度。CPU在运行过程中需要从外界读取数据,取数据的来源主要来自于:1)寄存器;2)Cashe;3)内存中,不过CPU访问内存的过程中大部分数据都要经过寄存器,然而这样相比直接访问寄存器就增加了数据访问的时间,我们前面的文章说过局部变量存在堆栈中,堆栈存在内存中,如果我们能够把变量放在寄存器中岂不可以加快访问速度。

    不过使用register关键字的时候需要注意如下几点:

    1)我们都知道&符号是取内存地址的意思,那么既然用register修饰一般就不能使用该符号进行访问。

    2)前面我们提到过C语言各个数据的存储方式,比如说全局变量或者静态变量等等都是在内存中有着具体的地址的,那么是否能够用register修饰呢?肯定不能进行修饰的,那么什么变量可以用该关键字修饰呢?答案是局部变量,前面的文章我也提到过局部变量是在函数运行过程中自动在栈上分配的,而栈也是在内存中为什么可以分配进寄存器?(哈哈,这三问可把我给问蒙了!)

    如上图所示,对于局部变量的生命周期很短,不会一直占用该寄存器,但函数1使用完还可以供函数2继续使用,从而大大提到运行速度。

    3)我们都知道芯片内部的寄存器是有限制的,而且每个寄存器都有特定的功能,能够供我们用来存变量的并不是很多,更何况并不是所有的类型的变量都可以存在寄存器中使用,这个需要根据具体的芯片来决定,比如浮点数就在大部分芯片中无法放到到寄存器中读写,所以说register仅仅只是告诉编译器该变量会频繁使用,建议放到寄存器中读写,至于具体是否存放需要编译器自行决定,所以有时候编译就会忽略该关键字。

    好了,还有一些注意事项可能需要举例说明,这里光说没啥用,来点实验。

3、实验现象看register效果

    写了一个简单的测试程序,也就是我们最开始学习编程用的循环延时,分别对局部变量使用register关键字修饰和不修饰来获得程序运行时间。(采用Dev_C++运行该程序)

  1. #include <stdio.h>

  2. #include <stdlib.h>

  3. /*************************************

  4. * Fuction: 测试register

  5. * Author : (公众号:最后一个bug)

  6. ************************************/

  7. int main(int argc, char *argv[]) {

  8. //register long cnt = 0;

  9. long cnt = 0;

  10. int timer = 0;

  11. for(cnt = 0;cnt < 100000000;cnt++)

  12. {

  13. timer++;

  14. }

  15. printf('欢迎关注公众号:最后一个bug!');

  16. return 0;

  17. }

不采用register修饰三次运行大致时间:

采用register修饰三次运行大致时间:

    简单解析一下:上面的结果仅仅是用于对比(作者运行程序使用的电脑还是读大学使用的电脑虽然换了固态和内存条,毕竟也是老古董了),我们可以看到使用register确实能够缩短程序执行时间,那么一些小伙伴们会问了前面说了register只是建议放到寄存器中读写,那么如何判断到底程序有没有放到寄存器中来运行程序呢?答案是三个字------'看程序的汇编'!!

4、Dev_C++如何查看C程序的汇编

    这里简单介绍Dev_C++的汇编查看功能主要是为下面的知识讲解做铺垫的,同时最近也发现很多小伙伴还在用VC++来进行学习,并且也遇到很多安装方面、系统兼容性问题,作者觉得如果只是为了学习,可以安装Dev_C++软件来进行实践,同时安装包小且安装过程也非常方便。

    对于Dev_C++的基础教程大家可以网络搜索学习一下,这里作者简单说一下其如何调试查看代码汇编?为了方便大家验证结果。

    1)在代码行序号前面打上端点,然后点击左下角的Debug,进入调试状态。

    2)进入调试模式一下,Debug选项卡里面的按钮都激活了,里面点击View CPU windows便可以弹出相对应的汇编语言窗口,同时点击Next instruction便会执行一下一条汇编指令,对于其他按钮的功能大致和我们平时调试的功能差不多,大家可以网络上搜索了解学习下,这里我就不多说了。

5、确定register是否生效?

    上面铺好了垫,确定register是否生效我们查看对应的汇编代码即可,如果我们对register修饰的变量的读写如果来自于寄存器,那么说明编译器进行了优化,如果是还是从对应的内存进行取值,那编译器就没有进行优化。下面我们简单看看修饰与不修饰的结果。

1)使用register修饰的汇编语句:

    解析一下:我们看到C语言中的cnt++变成了右边汇编中的add ebx,0x1;这样就说明确实把cnt放到了寄存器中使用。

2)不使用register修饰的汇编语句:

    解析一下:我们可以看到这里的cnt++是对esp+0x1c地址所在的内存取值并进行自加操作,这样我们最终获得上面的程序运行时间,后者明显要慢一些。

    这里再补充一点小知识 : 对于学习ARM的小伙伴应该知道ARM中传递函数参数大部分都是通过r0~r1寄存器来进行操作,其他更多的参数通过栈来进行传递,所以说我们有时候传入的参数尽量不要超过4个,以使得更多的处理在寄存器中,以提高程序运行的效率,这里只是简单提一下,后续我会出一篇如何提高程序运行效率的文章供大家阅读。

6、最后小结一下

    大家应该感觉到了,其实register本身其实真的很简单,根本没什么可讲的,不过由于他存在一定的模棱两可,所以才会有人会去证实,然而在证实的过程中,其实你学到的不仅仅只有这个关键字,还有很多附加的知识,比如程序的运行,编译器的处理等等,知识都是互联的,所以作者经常会把脉一下自己的知识体系来查漏补缺,而对于现代编译器很多时候都不会用到register关键字,编译器自动根据代码进行优化处理,不过如果你想按照自己的想法优化程序那还是需要了解清楚的。

    好了,今天的知识就分享到这里了,这里是公众号:“最后一个bug”,欢迎大家添加作者个人微信进行学习交流和建议反馈。感谢大家的关注,我们下期见!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多