• Linux | C语言中volatile关键字的理解


    目录

    前言

    一、代码引入

    二、现象解释

    三、具体引用


    前言

            本章主要讲解介绍volatile关键的作用与使用场合;深刻理解volatile关键字;本文你需要有信号相关的基础知识;

    Linux | 信号-CSDN博客

    一、代码引入

            首先,我们来查看下面这段代码;

    1. #include
    2. #include
    3. // 定义全局变量
    4. int flag = 1;
    5. void handler(int signum)
    6. {
    7. (void)(signum); // 防止编译器警告
    8. std::cout << "change before flag:" << flag << std::endl;
    9. flag = 0;
    10. std::cout << "change after flag:" << flag << std::endl;
    11. }
    12. int main()
    13. {
    14. // 对2号信号捕捉
    15. signal(SIGINT, handler);
    16. // 死循环
    17. while(flag);
    18. std::cout << "run here..." << std::endl;
    19. return 0;
    20. }

            当我们发送2号信号时,全局变量flag被改为了0,然后循环条件不满足,打印 run here 后退出;我们运行查看结果是否满足我们预期结果;如下所示;

            第一个红色框起来的是我们编译程序所用指令;第二个红色框起来的是当我们按下 ctrl + c 发送2号信号时,程序如我么预期所料;

            接下来,我们来介绍以下 gcc/g++ 的几个编译选项;如下图所示;

            -O1、-O2、-O3分别为编译时三个不同等级的优化,其中优化程度由低到高,我们选择最高等级,再次编译运行代码;如下所示;

            神奇的一幕发生了,我们发现我们无论按多少次 ctrl + c 都无法退出程序,我们发送2号信号,也被处理了,我们的全局变量flag不是被置为0了吗?为什么还是没有办法退出while循环呢?下面我们来仔细讲解这个神奇现象;

    二、现象解释

            实际上,这就是跟我们的编译器优化有关,我们把视角拉到代码中;如下图所示;

            我们的while循环判断分为以上三个步骤,而当我们编译时对代码采用 O3 级别的优化时,我们的编译器检测到循环中没有对全局变量flag进行修改,因此直接将上面的步骤优化成了如下所示;

            故即使我们发送2号信号将内存中的flag更改,但是判断时时候,依旧直接判断寄存器中flag的那个值;所以才会看到上述那种神奇现象;

    三、具体引用

            我们本文的主角volatile关键字就是为了防止这种编译器过度优化的现象,我们可以在定义flag变量的前面加上一个 volatile关键字,这样可以防止我们的变量flag参与被编译器编译的代码过度优化;

    1. #include
    2. #include
    3. // 定义全局变量(增加volatile关键字)
    4. volatile int flag = 1;
    5. void handler(int signum)
    6. {
    7. (void)(signum); // 防止编译器警告
    8. std::cout << "change before flag:" << flag << std::endl;
    9. flag = 0;
    10. std::cout << "change after flag:" << flag << std::endl;
    11. }
    12. int main()
    13. {
    14. // 对2号信号捕捉
    15. signal(SIGINT, handler);
    16. // 死循环
    17. while(flag);
    18. std::cout << "run here..." << std::endl;
    19. return 0;
    20. }

            代码几乎完全相同,就加入了一个volatile关键字,避免了这种编译器过度优化现象;

  • 相关阅读:
    《C++代码简洁之道》学习笔记:C++代码整洁的基本规范
    Linux-管理文件系统及存储
    【FPGA小波变换】基于FPGA的图像9/7整数小波变换verilog实现
    wf-docker集群搭建(未完结)
    redis企业级数据备份方案以及数据恢复
    搭建Python开发环境
    verilog 等价操作符
    Opengl之高级数据
    二叉树的基础讲解
    最优化基础知识总结(1)
  • 原文地址:https://blog.csdn.net/Nice_W/article/details/134490064