当前位置: 首页 > article >正文

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

目录

前言

一、代码引入

二、现象解释

三、具体引用


前言

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

Linux | 信号-CSDN博客

一、代码引入

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

#include <iostream>
#include <signal.h>

// 定义全局变量
int flag = 1;

void handler(int signum)
{
    (void)(signum); // 防止编译器警告
    std::cout << "change before flag:" << flag << std::endl;
    flag = 0;
    std::cout << "change after flag:" << flag << std::endl;
}

int main()
{
    // 对2号信号捕捉
    signal(SIGINT, handler);
    
    // 死循环
    while(flag);

    std::cout << "run here..." << std::endl;
    return 0;
}

        当我们发送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参与被编译器编译的代码过度优化;

#include <iostream>
#include <signal.h>

// 定义全局变量(增加volatile关键字)
volatile int flag = 1;

void handler(int signum)
{
    (void)(signum); // 防止编译器警告
    std::cout << "change before flag:" << flag << std::endl;
    flag = 0;
    std::cout << "change after flag:" << flag << std::endl;
}

int main()
{
    // 对2号信号捕捉
    signal(SIGINT, handler);
    
    // 死循环
    while(flag);

    std::cout << "run here..." << std::endl;
    return 0;
}

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


http://www.kler.cn/a/133497.html

相关文章:

  • 提高数据处理效率:JavaScript 操作 XLSX 文件的最佳实践
  • SQL面试题——蚂蚁SQL面试题 会话分组问题
  • Kettle配置数据源错误“Driver class ‘org.gjt.mm.mysql.Driver‘ could not be found”解决记录
  • fastadmin多个表crud连表操作步骤
  • ARM架构中断与异常向量表机制解析
  • Linux网络——网络初识
  • 盘点54个Python实用工具源码Python爱好者不容错过
  • PPT基础入门
  • F. Alex‘s whims Codeforces Round 909 (Div. 3) 1899F
  • 如何在Jupyter Lab中安装不同的Kernel
  • 限制Domain Admin登录非域控服务器和用户计算机
  • 【jvm】MinorGC、MajorGC和FullGC
  • OceanBase:Zone管理
  • GPT实战系列-P-Tuning本地化训练ChatGLM2等LLM模型,到底做了什么?(二)
  • STM32/N32G455国民科技芯片驱动DS1302时钟---笔记
  • 实验11 SQL互联网业务查询-2
  • 虚拟机配置网络ip,主打一个详细
  • 2023年汉字小达人市级比赛在线模拟题更新:40分钟150题完整对标
  • Cascade-MVSNet论文笔记
  • 基于适应度相关算法优化概率神经网络PNN的分类预测 - 附代码
  • 数据挖掘复盘——apriori
  • IDEA插件推荐:Apipost-Helper
  • “释放视频潜力,批量放大视频尺寸,高效提升视频质量“
  • 类模板与友元
  • Android 获取系统编解码器
  • Argo Rollouts结合Service进行Blue-Green部署