static与volatile的用法
static
1、概述
static 声明的变量在C语言中有两方面的特征:
1)、变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。
2)、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。
2、问题:Static的理解
关于static变量,请选择下面所有说法正确的内容:
A、若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
B、若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
C、设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题;
D、静态全局变量过大,可能会导致堆栈溢出。
答案与分析:
对于A,B:根据本篇概述部分的说明b),我们知道,A,B都是正确的。
对于C:根据本篇概述部分的说明a),我们知道,C是正确的(所谓的函数重入问题,下面会详细阐述)。
对于D:静态变量放在程序的全局数据区,而不是在堆栈中分配,所以不可能导致堆栈溢出,D是错误的。
因此,答案是A、B、C。
3、问题:不可重入函数
曾经设计过如下一个函数,在代码检视的时候被提醒有bug,因为这个函数是不可重入的,为什么?
unsigned int sum_int( unsigned int base )
{
unsigned int index;
static unsigned int sum = 0; // 注意,是static类型的。
for (index = 1; index <= base; index++)
{
sum += index;
}
return sum;
}
答案与分析:
所谓的函数是可重入的(也可以说是可预测的),即:只要输入数据相同就应产生相同的输出。
这个函数之所以是不可预测的,就是因为函数中使用了static变量,因为static变量的特征,这样的函数被称为:带“内部存储器”功能的的函数。因此如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量,这种函数中的static变量,使用原则是,能不用尽量不用。
将上面的函数修改为可重入的函数很简单,只要将声明sum变量中的static关键字去掉,变量sum即变为一个auto 类型的变量,函数即变为一个可重入的函数。
当然,有些时候,在函数中是必须要使用static变量的,比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。
volatile
volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
volatile译为:易变的。在前面加上关键字volatile之后告诉编译器,用volatile修饰的变量是易变的,不要对此变量进行优化,每次都要到变量的地址中去读取变量的数据,但正因为这样,才是保持了变量的原样,因为变量已经发生改变了,你却操作的是没有变化时的数据,这样才让变量失去了本应该保持的属性。
eg:
int a=1;
a=2;
a=3;
....
编译器看到这样的代码,会觉得a的值只有a=3才有意义,所以把a存储在一个寄存器中,每次遇到a都在这个寄存器中去读取数据,但是a是可能改变,比如中断或者多线程的时候。这个有可能你测试它又是正确的,因为随着你的优化等级提高,生成的汇编代码会有很大不同,如果基础不够扎实,代码的鲁棒性就会减弱,要想不这样,那么需要程序员有足够扎实的基本功。
1.我们先看volatile第一个应用场景,在中断服务函数中的使用。
/* main.c */
int flag=0;
int main(void)
{
if(flag==1)
{do somethings}
if(flag==2)
{do somethings}
return 0;
}
/* interrupt*/
void NVIC_Handler(void)
{
flag=1;
}
在这种情况下,编译器可能会对其做优化,虽然中断服务函数改变了flag的值,但是编译器并没有在变量内存中去读取,而是在寄存器中读取了flag之前的缓存数据。在中断函数中的交互变量,一定要加上volatile关键字修饰,这样每次读取flag的值都是在其内存地址中读取的,确保是我们想要的数据。
2.多任务环境下各任务间共享的标志应该加volatile。原因其实和上面中断一样,要共享标志,又不想让编译器优化了这一点,需要加上该修饰词。
3.存储器映射的硬件寄存器通常也要加voliate,因为每次对它的读写都可能有不同意义。
以STM32为例,寄存器中的数据也是时刻在变化的,我们也不想编译器优化这一点,所以在库函数中我们可以看到这样的代码。

这是寄存器的结构体,我们查看前缀__I 和__IO到底是什么?

可以看到,在寄存器的映射中,也需要volatile,因为寄存器的值也是可能随时更改的。
通过上面,我们也应该明白那个问题。
一个参数既可以是const还可以是volatile吗?
可以的,例如只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。软件不能改变,并不意味着我硬件不能改变你的值,这就是单片机中的应用。
static与volatile的用法的更多相关文章
- volatile的用法
在再有人问你Java内存模型是什么,就把这篇文章发给他中我们曾经介绍过,Java语言为了解决并发编程中存在的原子性.可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如synchronized ...
- 《OOC》笔记(1)——C语言const、static和extern的用法
<OOC>笔记(1)——C语言const.static和extern的用法 C语言中const关键字用法不少,我只喜欢两种用法.一是用于修饰函数形参,二是用于修饰全局变量和局部变量. 用c ...
- C++ 中 static 与 const 的用法及对比
在这个学习过程中我对 static 及 const 的使用时常会混淆,因此整理,加深记忆 一.类的静态成员 如果某个属性为整个类所共有,不属于任何一个具体对象,则采用 static 关键字来声明静态成 ...
- c中常用的关键字static const volatile
在C语言中,关键字static有三个明显的作用:1). 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变.2). 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数 ...
- [Android Pro] static 和 Volatile 的区别
reference to : http://blog.sina.com.cn/s/blog_4e1e357d0101i486.html static也是各个业务方可以去全局修改: volatile是处 ...
- static \ const \ volatile 的含义
1.static 在函数体内,一个被声明为静态的变量在这一函数被调用的过程中维持其值不变 在模块内(函数体外),一个被声明为静态的变量可以被模块内的所有函数访问,但不能被模块外的其他函数访问,即它是一 ...
- static和extern的用法小结
以前写程序是,基本不管static和extern,一个工程文件也只有一个c文件.今天尝试用多个文件来写,自然就涉及到这两个关键词的使用,自己查了些资料,并且做了些实验,总结如下. extern的用法 ...
- Java 中 static 和 volatile 关键字的区别?
static指的是类的静态成员,实例间共享 volatile跟Java的内存模型有关,线程执行时会将变量从主内存加载到线程工作内存,建立一个副本,在某个时刻写回.valatile指的每次都读取主内存的 ...
- const,static,volatile关键字的作用
const关键字: 1.欲阻止一个变量被改变,可使用const,在定义该const变量时,需先初始化,以后就没有机会改变他了: 2.对指针而言,可以指定指针本身为const,也可以指定指针所指的数据为 ...
随机推荐
- 搬运,B站up主『凉风有性胖次君』日日日日日日日日日日在校园
这个视频超有毒,简直丧心病狂,我竟无言以对,凉风是有多大的耐性,搜集了这么多元素,哈哈哈~~~赶紧搬运,怕哪天B站都给封了 也就是说世界本来喜欢的是言叶,但是言叶爱上了一直在电车上暗恋她的诚哥,于是世 ...
- sqlalchemy的使用
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index ...
- day13.装饰器进阶,迭代器
1.from functools import wraps 这个函数可以保留原来函数的属性 # from functools import wraps def car_time(fun): # @wr ...
- asp.net core Csc任务不支持SharedCompilationId参数,请确认改参数存在于此任务中,并且是可设置的公共实例属性
创建Asp.net Core2.0版本项目时,成功创建后编译时出现如下问题 解决方法 Nuget上安装Microsoft.Net.Compilers
- asp+SqlServer2008开发【第三集:win2winSSH远程连接—像连接Linux一样操作】
1,参考:https://blog.csdn.net/flyingshuai/article/details/72897692 和https://blog.csdn.net/nijiayy/artic ...
- Servlet(六):Cookie
Cookie 学习:问题: HTTP 协议是没有记忆功能的,一次请求结束后,相关数据会被销毁.如果第二次的请求需要使用相同的请求数据怎么办呢?难道是让用户再次请求书写吗?解决: 使用 Cookie 技 ...
- C语言编译器CL.exe
下载地址CL.7z版权问题:仅供学习交流,请于24小时内删除,本人不承担版权问题… 基本使用: 1.解压缩,例如解压缩到E盘根目录下 2.打开cmd命令行界面(快捷方式win+R输入cmd回车)cd命 ...
- 移动端click事件清除
http://blog.csdn.net/zfy865628361/article/details/49512095
- [POJ1050]To the Max (矩阵,最大连续子序列和)
数据弱,暴力过 题意 N^N的矩阵,求最大子矩阵和 思路 悬线?不需要.暴力+前缀和过 代码 //poj1050 //n^4暴力 #include<algorithm> #include& ...
- 认识vim 编辑器
vim编辑器 vim编辑器的重点是光标的移动,模式切换,删除,查找,替换,复制,撤销命令的使用. vim 有三种模式: 命令模式,编辑模式,末行模式 vim打开方式: 语法: vim 文件路径 vim ...