搜索
bottom↓
回复: 14

C语言const和volatile关键字使用疑惑

[复制链接]

出0入0汤圆

发表于 2017-4-25 10:39:01 | 显示全部楼层 |阅读模式
问题1:如下需要使用const和volatile关键字嘛?
解释:如果我在程序中定义一个缓存(全局变量或者全局结构体),我需要使用volatile嘛?为什么...

问题2:什么情况下使用const和volatile关键字?
解释:st库在定义结构体时针对寄存器变量(这个地址对应的内存是个单片机某个外设寄存器)一般会使用volatile,但是很少有使用const...
C库函数在操作字符串指针时喜欢在定义函数体时使用const对形参进行修饰(例如定义一个uint8_t * const str,那么我们就不能做str++等操作),但是很少在C库中看到volatile...
我想知道,到底是在定义变量或者结构体成员时进行修饰,还是应该在定义函数时针对函数形参进行修饰?哪一种场合更合适?还是说要看情况讨论?

描述的不是很清楚,由于自己平时在写代码的时候很少会使用const和volatile,所以之前也没认真考虑过,还请大神帮忙指导下,在此感谢了...

出25入84汤圆

发表于 2017-4-25 10:43:31 | 显示全部楼层
volatile主要用在系统优化时,比如delay (){for(i=0;i<10;i++)}如果 i 没有定义为volatile ,那在优化时系统会认为你这个delay里面的循环是多余的(没有干任何事)就会帮你去掉这里面的语句,i定义为volatile ,则必须无条件执行

出25入84汤圆

发表于 2017-4-25 10:45:09 | 显示全部楼层
const比如你取字模了一张图片放在内存中,你不希望程序或者其他东西来改变它,那么你可以定义为const,主要是防范风险,你不用也可以。

出0入93汤圆

发表于 2017-4-25 10:46:11 | 显示全部楼层
在网上搜搜吧,这两个的专门解释有很多的

出0入4汤圆

发表于 2017-4-25 10:56:45 | 显示全部楼层
const 还是很好理解的,就是常量 。只能读不能写 。一般是存在flash里的。  比如字模啊,固定的数组啥的。

出0入0汤圆

发表于 2017-4-25 11:10:00 | 显示全部楼层
const 是只读。

volatile 是每回调用的时候都要从变量那里读,一般用于中断改变变量的时候。

比如:
char a, b;
volatile char c;

a= b+c;
.
.
.
a = b+c;

如果c不是volatile, 优化时很可能第二个 a=b+c;就不计算了。
如果c用volatile修饰,就要重新计算一遍。

出0入0汤圆

发表于 2017-4-25 11:11:12 | 显示全部楼层
volatile 还是很好理解的
比如定义一个 变量 char rxFinished = 0; 表示串口之类的接受数据完成。

如果你想等串口接收完成可以写

while(rxFinished  != 0) {
// 循环体内的操作不改变 rxFinished 的值
}

因为循环体内并不会改变rxFinished  值, 因为程序是顺序执行的, 编译器认为这个值在这个过程中并不会被改变, 所以编译优化的时候它可能把这个值加载到寄存器中(而且只加载一次,因为并不会被改变,所以没必要再次去读取内存)。

但是除了顺序执行的代码, 还有中断, 所以哪怕你在串口接收中断中把rxFinished置为1, while 循环依然不会退出, 就是死循环了。 而且经常发生debug模式下代码行为是正确的, release 模式下生成的代码就异常了, 就是后者优化掉了。

出0入0汤圆

发表于 2017-4-25 11:13:07 | 显示全部楼层
用 const 修饰指针的情况也很多

出0入0汤圆

 楼主| 发表于 2017-4-25 11:37:16 | 显示全部楼层
感谢楼上各位神指教

出590入992汤圆

发表于 2017-4-27 17:43:32 | 显示全部楼层
我来解释下,
1:const修饰的变量,主要目的是在编译阶段作用,本质是还是变量,既然不能修改,为什么不定义为常量呢?主要的目的就是:防止被用户意外修改(这个意外指的编译阶段!实际中有可能被指针访问内存改变!)
2:volatile 表示这个值是易变的,主要和编译器优化相关,高等级优化程度会优化掉一些‘没有用’的代码,比如:for(u8 i=0;i<100;i++);本质是想延时,但是编译器认为这一句没有效果(i这个变量只在这一句用到,而且自生自灭,所以就省略到这句),如果加了volatile就表示这个变量 i 可能在其它地方也用到(比如用指针访问内存的方式),于是就仍然执行这一个代码。

出0入0汤圆

 楼主| 发表于 2017-4-27 18:44:11 | 显示全部楼层
我觉得10楼说的很有道理
比如,我们可以修饰一个IO口寄存器的地址为 const volatile,如果这算是常量的话,如何理解这里使用volatile?
无外乎是这里不能使用软件进行修改,言外之意,硬件可以修改这个地址中的内容.
所以const应该说是只读的,而不应该说的常量.
不知道说的是否正确,还请大神指教~~~

出0入93汤圆

发表于 2017-4-27 18:58:36 | 显示全部楼层
擦鞋匠 发表于 2017-4-27 18:44
我觉得10楼说的很有道理
比如,我们可以修饰一个IO口寄存器的地址为 const volatile,如果这算是常量的话,如 ...

你理解的是对的。
C语言就特么一个坑B。const其实就仅仅只是readonly而已,修饰的是一个变量,而且仅仅是对程序员的一种非强制约定。
至于神马IAR、MDK、Cosmic之类的放到flash,都是不标准的用法,是资源受限的一种折衷,当然他们美其名曰“扩展语法”。

出0入0汤圆

发表于 2017-4-27 19:31:25 | 显示全部楼层
takashiki 发表于 2017-4-27 18:58
你理解的是对的。
C语言就特么一个坑B。const其实就仅仅只是readonly而已,修饰的是一个变量,而且仅仅是 ...

C11草案,N1570,6.7.3-4之注释132:
The implementation may place a const object that is not volatilein a read-only region of storage.
Moreover, the implementation need not allocate storage for such an object if its address is never used.

const的object在Flash中是完全符合标准的。

出0入0汤圆

发表于 2017-4-27 20:03:50 | 显示全部楼层
const就是对应的object(变量)是只读的。
- 如果只用到Object的值,但是没用到其地址,编译器可以把其值当作字面常量,不分配存储器。
- 如果用到Object的地址,或编译器就是愿意,则分配对应的存储器,此时编译器只约束对这个Object不能有写操作;通过指针等方式间接的写操作是可能的(这点没人管了)。


volatile简单来说就是Object本身可能被外部修改(当前运行环境之外,如另一个线程/进程/处理器/外部电路,etc)或者对它的操作(读或者写)有特殊的副作用。
例如,外部输入的寄存器;实现是标准的Memory,但是读/写操作本身会触发某种额外的操作(比如逻辑电路监视地址线/读写信号线的情形,etc)。

所以,编译器必须保证对volatile object的操作出现在外部,即不能优化其对内存的访问操作,必须让处理器使用这个指令。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-19 22:35

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表