C语言之const和volatile"究极"学习


关于const的用法,如今大概前先后后应该写了有两篇文章,之前学习的时候,用法体会不是那么深入,为啥这么说呢,由于在学习c++的时候,会发现const关键字有新的玩法,关于这个新的玩法,你们能够去看最近学习总结写的c++文章专辑。c++

1、const的用法:web

一、const只读变量:面试

  • const修饰的变量是只读的,本质上仍是变量数组

  • const修饰的局部变量在栈上分配空间微信

  • const修饰的全局变量在全局数据区分配空间编辑器

  • const只在编译期有用,在运行期没有用函数

注:const修饰的变量不是真的常量,它只是告诉编译器该变量不能出如今赋值符号的左边学习

二、const全局变量的分歧:flex

  • 在现代c语言编译器中,修改const全局变量将致使程序崩溃优化

  • 标准c语言编译器不会将const修饰的全局变量存储于只读存储区中,而是存储于可修改的全局数据区,其值依然能够改变

三、代码示例:

(1)只读变量代码示例:

#include <stdio.h>

int main()
{
   const int a =10;
   printf("a = %d\n",a);

   a=20;
   printf("a = %d\n",a);
  
  return 0;
}

运行结果:

test.c: In function ‘main’:
test.c:8:4: error: assignment of read-only variable ‘a’
    a=20;
    ^

注解:显示这个结果很正常,变量a被const修饰了,它就成了只读的。

(2)若是对变量a的值进行修改:

#include <stdio.h>

int main()
{
   const int a =10;
   int *p =(int *) &a;
   printf("a = %d\n",a);

   *p=20;
   printf("a = %d\n",a);


  return 0;
}


运行结果:

root@txp-virtual-machine:/home/txp# ./a.out
a = 10
a = 20

注解:经过指针的方式,就可以把a的值进行修改,这也论证了“const修饰的变量是只读的,本质上仍是变量”这句话

(3)const修饰全局变量:

代码版本一

#include <stdio.h>
const int b = 40;

int main()
{
   
 
   printf("b = %d\n",b);
   b=20;
   printf("b = %d\n",b);


  return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp# gcc test.c
test.c: In function ‘main’:
test.c:10:4: error: assignment of read-only variable ‘b’
    b=20;
    ^

注解:跟const修饰栈上的变量用法同样

代码版本二

#include <stdio.h>
const int b = 40;

int main()
{

   int *p =(int *) &b;
   printf("b = %d\n",b);

   *p=20;
   printf("b = %d\n",b);


  return 0;
}

运行结果:

root@txp-virtual-machine:/home/txp# ./a.out
b = 40
Segmentation fault (core dumped)

注解:这里出现了段错误,这也验证了咱们上面所说的“修改const全局变量将致使程序崩溃”。

同时为了验证“标准c语言编译器不会将const修饰的全局变量存储于只读存储区中,而是存储于可修改的全局数据区,其值依然能够改变”这句话,我把这段代码放到dev c++上进行试验:

说明:我这个版本的编译器支持标准c语言,因此没致使程序崩溃,可以正常运行

四、const的本质

  • c语言中的const使得变量具备只读属性

  • 现代c编译器中的const将具备全局生命周期的变量存储于只读存储区,不是放在全局数据区

注:const不能定义真正意义上的常量;同时这里注意static关键字修饰的变量,它的生命周期和全局变量同样。

代码示例:

#include <stdio.h>

const int Array[5] = {0};

void fun(int *p,int v)
{
   *p=v;
}
int main()
{
    int const i =1;
    const static int j =2;
    int const array[5] = {0};

    fun((int *)&i,1);
    fun((int *)&j,2);
    fun((int *)&array[2],3);
    fun((int *)&Array[1],4);

   return 0;

}

输出结果:

root@txp-virtual-machine:/home/txp# ./a.out
Segmentation fault (core dumped)

注解:这里会有段错误,错误出如今const+static修饰的j变量对其进行修改,还有const修饰的全局数组。

五、const修饰函数参数和返回值

  • const修饰函数参数表示在函数体内不但愿改变参数的值

  • const修饰函数返回值表示返回值不可改变,多用于返回指针的情形

在c语言中的字符串字面量存储于只读存储区中,在程序中须要使用const char* 指针,例如:

const char * s = "TXP嵌入式";//字符串字面量

代码示例:

#include <stdio.h>

const char*fun(const int i)
{
   i=8;
    return "TXP";
}
int main()
{
   const char * p=fun(0);
    printf("%s\n",p);
    p[1]='_';
    printf("%s\n",p);

    return 0;


}


输出结果:

root@txp-virtual-machine:/home/txp# gcc test.c
test.c: In function ‘fun’:
test.c:5:4: error: assignment of read-only parameter ‘i’
    i=8;
    ^
test.c: In function ‘main’:
test.c:12:5: error: assignment of read-only location ‘*(p + 1u)’
     p[1]='_';
     ^

注解:上面这样写,确定有问题。

代码进化:

#include <stdio.h>

const char*fun(const int i)
{
//   i=8;
    return "TXP";
}
int main()
{
   const char * p=fun(0);
    printf("%s\n",p);
  //  p[1]='_';
   // printf("%s\n",p);

    return 0;


}

输出结果:

root@txp-virtual-machine:/home/txp# ./a.out
TXP

2、volatile的用法

老实说,这个关键字在面试题目里面常常会出现,可是平时学习的时候,若是你没有真正理解这其中的含义,在笔试的时候,脑壳里面可能依稀是记得有那么几个结论,可是有时候吧,一紧张就把结论给忘了,也不是不可能,因此说,咋们仍是老实一点,得真正把它原理搞明白才行,这样上来战场就不怕了,之后写代码也就少一点bug。

一、volatile的经常使用结论(volatile英文本意就是易变的意思)

这里我先给结论,而后再给一个例子,把这个例子的讲明白,全部结论就都明白了。

  • volatile可理解为“编译器警告指示字”

  • volatile告诉编译器必须每次去内存中取变量值

  • volatile主要修饰可能被多个线程访问的变量

  • volatile也能够修饰可能被未知因素更改的变量

  • volatile能够修饰一个中断子程序中会访问到的非自动变量

二、分析原理

你们可能平时在博客学习,都会发现讲解编译器优化的,而后加了volatile关键来修饰变量,就告诉编译器不要去优化这个变量了,那么这里的优化究竟是什么意思呢?

从字面上来理解优化两个字,意思就是最优值(变量的值不会改变),这里我用一个简单代码来讲明一下:

#include <stdio.h>

int main()
{
    int a =1;//volatile int a =0;
     
    while(a)
    {
    
    }
}

说明:上面的代码,若是变量a没有加volatile修饰的话,编译器就会优化它(也就是a的值一直不变),因此while就一直死循环;而后我若是加了volatile来修饰的话,编译器就不会去优化变量a,不优化的意思就是说,变量a的值可能就会改变,while就不会一直死循环。

固然这里为了好理解,我说的不是很专业,没有从寄存器和内存的角度去说。(我也不想那么去讲解,简单理解了就行)

总之一句话:上面的结论中,volatile修饰的都是变量,变量就可能改变,不会被编译器优化;只是说咱们上面的结论应用场景不一样而已。

3、总结

  • const使得变量具备只读属性

  • const不能定义真正意义上的常量

  • const将具备全局生命周期的变量存储于只读存储区

  • volatile强制编译器减小优化,必须每次从内存中取值


好了,今天的分享就到这里,若是文章中有错误或者不理解的地方,能够交流互动,一起进步。我是txp,下期见!

本文分享自微信公众号 - TXP嵌入式(txp1121518wo-)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索