volatile、const关键字的理解

一个程序中数据的计算是通过CPU。那么CPU中的数据来自哪里呢?

  1. 内存(物理内存):所以一个进程的虚拟内存操作后会通过MMU将虚拟内存中的数据映射到物理内存

  2. 寄存器(cpu的寄存器):当一个变量的优化级别较高时,会将变量存到cpu的寄存器中

用信号理解volatile

代码说明:

#include <stdio.h>

int flag = 0;
void sig_handle(int signo)
{
    printf("signo = %d\n",signo);
    flag = 1;
}

int main()
{
    signal(2,sig_handle);
    while(!flag)
        ;
    return 0;
}

这个程序想要的效果是主函数阻塞,当按了ctl+c后,程序结束。

但实际上是当按下ctl+c后,回打印printf语句,程序不会结束。

原因:

main函数和和信号处理函数是两个执行流,while循环在main函数中,编译器只会检查main函数,发现flag并没有main函数中改变。在优化级别较高的时候,flag会被直接写进cpu的寄存器中,cpu读取flag时直接从寄存器里读,信号处理函数改变flag改变的是flag在内存中的值,寄存器中flag的值始终保持0。

 

程序改进:

#include <stdio.h>

volatile int flag = 0;
void sig_handle(int signo)
{
    printf("signo = %d\n",signo);
    flag = 1;
}

int main()
{
    signal(2,sig_handle);
    while(!flag)
        ;
    return 0;
}

 

直接解释volatile:

vilatiele:易变的,说明被volatile修饰的变量在程序运行过程中可能会被改变。所以每次在读值的时候,都要去内存中拿,这样拿到的值才是正确的(防止编译器优化))。

int main()
{
    int a = 1;
    int b = a;
    int c = a;
    return 0;
}
计算机的惰性原则,为了计算速度往往不会去执行没用的操作,在优化代码的时候它发现b和c的值都是等于a的,所以在执行int b=a的时候他会到内存中把a的值1取出来赋值给b,这一点没什么毛病,但是下一条语句它发现c也是等于a的,本来按照刚刚的流程进到内存里面把a拿出来再给c就可以了,但是编译器发现执行int b=a的时候已经拿过一次a了,并且a的值还没有改变,那它为了省事它就不到内存去拿,而是把刚刚拿出来在缓存里的a给c,这样就减少了一个读取的操作,提高了效率。
int main() { volatile int a = 1; int b = a; int c = a; return 0; }
声明volatile变量a的时候,就是告诉编译器这个变量可能在运行的时候会被改变(防止优化),所以对a操作的时候都是去内存取值,即b=a,c=a都是从内存中读取a的值,这样就能确保我们拿到的是变化后的值

 什么时候使用volatile?

  1. 多线程中共享的变量

  2. 中断服务子程序中会访问到的非自动变量

  3. 并行设备的硬件寄存器(如:状态寄存器)

 

const关键字:

const:常量变量,用const修饰的变量是只读变量,不能修改

1. 修饰变量:

  const int a = 1;//定义并初始化一个常变量a

  a = 2;//错误,a为只读,不能修改

  const int b;//错误,const修饰的变量在定义的时候必须初始化

2. 修饰函数的参数:

  void setmu(const int a)//在这个函数中不能对a进行修改

  {

    a = 1;错误,不能改变

  }

3. 修饰函数:

  const修饰函数,说明函数的返回值不能修改,并且该返回值只能用带const的变量接收

  const char getstring();

  char *str = getstring()//错误,因为str没有const修饰

  const char *str = getstring()//这样就正确

4. 修饰指针

  a.常量指针:指针指向的那块地址内容不能被改变(既不能用*p去改变地址里的内容),但是这个指针变量本身却可以指向多个地址

  理解:const修饰的*p,所以指向的那块地址里的内容不能修改

    int const *p;

    const int *p;//这两个是一样的

    如:int a = 3;

      int b = 4;

      int const *pa = &a;

      *pa = 4;//错误,不能通过*pa改变他指向的那块地址的值

      printf(“*pa = %d\n”,*pa);//输出3

      a = 4;

      printf(“*pa = %d\n”,*pa);//输出4

      pa = &b;//可以指向多个地址

      

  b.指针常量:这个指针变量的值不能改变(即只能指向一个确定的地址了),但是指向的那块地址的内容可以改变

  理解:修饰的是p,所以p的值不能改变

    int *const p;

    如:int a = 2;

      int b = 1;

      int *const pa = &a;

      *pa = 6;//对的

      pa = &b;//错误,现在是指针常量

 

  int const * p const;

  int const * const p;//指针指向的内容和指针本身都不能改变

  

posted @ 2023-02-21 10:22  踏浪而来的人  阅读(48)  评论(0编辑  收藏  举报