C语言深入浅出的理解和高效的使用volatile关键字

一、摘要

本文将深入浅出的讨论什么是c语言的volatile关键字,并介绍在什么场景下需要使用到volatile关键字。本文将围绕如下内容展开:
1.c编译器的自动优化功能
2.volatile关键字的作用
3.volatile关键字的使用场景
在这里插入图片描述

二、编译器的自动优化功能

利用高级语言(如c、c++)进行编程,需要通过编译器将代码转成计算机能够识别的机器语言才能在计算机中运行。随着编译器的升级迭代,编译器在编译过程中会对代码自动优化,以提高代码的运行效率。编译器可以进行如下方面的优化:

1.提高程序的执行速度
通过减少指令数量(编译器会对代码进行分析,通过合并、消除冗余指令等方式,减少程序执行时所需的指令数量。)和指令调度的优化(编译器会重新排列指令顺序,以更好地利用CPU 的流水线架构,减少 CPU 的空闲时间,提高指令执行的并行度。)来提高程序的执行速度。

2.降低内存占用
通过变量存储优化(编译器会分析变量的生命周期和使用频率,合理安排变量的存储位置,减少不必要的内存占用。例如,对于一些只在局部范围内使用且生命周期较短的变量,编译器可能会将其存储在寄存器中,而不是栈内存中,这样可以减少栈空间的使用。)和代码压缩(编译器会对代码进行压缩,去除不必要的代码段和数据,减少可执行文件的大小。例如,对于一些未使用的函数和变量,编译器会在编译过程中将其去除,从而减小最终生成的可执行文件的体积。)的方式,来降低内存的占用。

3.提高资源利用率
通过缓存优化(编译器会根据硬件缓存的特性,对代码进行优化,提高数据和指令在缓存中的命中率。)和并行性利用(对于支持多核心 CPU 的系统,编译器会尝试识别代码中的并行部分,并进行并行化优化,使程序能够充分利用多核 CPU的计算能力,提高程序的整体性能。)的方式来提高资源的利用率。

4.增强代码的可移植性和兼容性
通过跨平台优化(不同的硬件平台和操作系统可能具有不同的特性和限制,编译器会根据目标平台的特点对代码进行优化,确保代码在不同平台上都能高效运行。)和标准兼容性(编译器会遵循C 语言标准和相关规范,对代码进行优化的同时保证代码的兼容性。)的方式来增强代码的可移植性和兼容性。

编译器的自动优化功能在大多数情况下是有利的,在在某些场景下如果进行了优化则可能会出现问题。比如如下优化:

5.读取操作的优化
寄存器缓存优化:
编译器在编译代码时,为了提高访问速度,可能会将变量的值缓存到寄存器中。后续对该变量的读取操作,编译器可能会直接从寄存器中获取值,而不是再次从内存中读取。但如果变量的值可能会被意外修改(如被硬件、中断服务程序或其他线程修改),这种优化就会导致程序读取到过期的数据。
循环内读取优化:
在循环中,如果一个变量的值在循环内部没有被修改,编译器可能会将该变量的读取操作移到循环外部,以减少不必要的内存访问。但如果该变量的值可能会在循环外部被修改,这种优化就会导致程序出现错误。

6.写入操作的优化
延迟写入优化:
编译器可能会为了提高性能,将对变量的写入操作延迟执行,先将值存储在寄存器或缓冲区中,等到合适的时机再将其写入内存。但如果变量的值需要立即反映到内存中(如对硬件寄存器的写入操作),这种优化就会导致硬件无法及时接收到正确的值。
写入合并的优化:
编译器可能会将多个对同一变量的写入操作合并为一个操作,以减少内存访问次数。但如果这些写入操作有先后顺序要求,或者中间可能会有其他因素影响变量的值,这种优化就会破坏程序的正确性。

三、volatile关键字的作用

volatile 关键字的核心作用在于阻止编译器对变量访问进行优化,保证每次对变量的读写操作都直接与内存进行交互,而不是使用寄存器里的缓存值。这样能确保程序在运行时能获取到变量的最新值。
简单来说就是使用volatile关键字修饰的变量就不进行优化了,程序对该变量的读写操作都直接通过内存进行,保证数据的正确性。

四、volatile关键字的使用场景

基于volatile关键字的作用以及编译器的自动优化特性,volatile关键字常用于对数据实时性更新以及多线程访问的场景。主要有如下几个方面:

4.1 硬件寄存器访问

在嵌入式开发中,经常需要访问寄存器的值,通常的做法是创建一个变量来保存寄存器的值。寄存器的值在任何时候都可能发生变化。如果不使用volatile进行修饰,编译器的自动优化可能导致数据没法及时更新。

4.2 多线程或中断服务程序

在多线程环境或者有中断服务程序的系统中,一个变量可能会被多个线程或者中断服务程序修改。如果不使用 volatile,编译器可能会将变量的值缓存到寄存器中,使得其他线程或中断修改该变量后,当前线程无法及时感知。
如下代码所示:

/*
*   project:        volatile_test
*   description:    This programmer is used to test volatile
*   author:         Conbiao                
*/

#include <stdio.h>
#include <pthread.h>

volatile int share_value = 0;

void* thread_function(void* arg)
{
    for(int i = 0; i <  1000000; i++)
    {
        share_value++;
    }

    return NULL;
}

int main(void)
{
    int ret = 0;

    pthread_t thread;

    pthread_create(&thread, NULL, thread_function, NULL);

    pthread_join(thread, NULL);

    printf("share_value = %d\n",share_value);

    return ret;
}

4.3 信号处理函数

信号处理函数可以在程序运行的任何时刻被调用,从而修改某些变量的值。使用 volatile 能确保在信号处理函数修改变量后,主程序能及时获取到新的值。
参考代码如下:

#include <stdio.h>
#include <signal.h>

// 定义一个 volatile 变量
volatile sig_atomic_t flag = 0;

// 信号处理函数
void signal_handler(int signum) {
    flag = 1;
}

int main() {
    // 注册信号处理函数
    signal(SIGINT, signal_handler);

    // 等待信号
    while (!flag) {
        // 执行一些操作
    }

    printf("Received signal, exiting...\n");

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值