在阅读时我遇到了这种类型的声明和以下行 -
const volatile char *p=(const volatile char *) 0x30;
p的值仅由外部条件改变
我没有得到什么是外部条件。还有这种声明的实际用途?
答案 0 :(得分:59)
const
表示程序流程不会修改p
指向的内容。在取消引用指针后修改该值的任何尝试都将导致编译时错误:
*p = 'A'; // will not compile
请注意,这不是一个特别强大的合同;位置0x30
的值仍然可以通过除p
以外的别名非常量指针来更改:
volatile char *q = 0x30;
*q = 'A'; // will compile
违反此合约的另一种方法是从const
转移p
:
*(volatile char *) p = 'A'; // will compile
但是,volatile
不排除可能由另一个线程,内核,异步信号处理程序或可访问相同内存空间的外部设备引起的任何修改。这样,编译器就不能做出错误的假设,即p
指向的值不会改变,并且每次引用时都会从内存中加载它:
/*
The character at 0x30 will be read on every iteration,
even if the compiler has proven that the program itself
doesn't modify the value at that address.
*/
while (*p) {
...
}
如果编译器错误地优化了这样的构造,它可以发出指令,这些指令只从存储器加载一次值,然后将其保存在寄存器中。寄存器本质上是一个独立的副本,对原始位置的任何更改都不会反映在那里,不用说,这可能会导致一些非常讨厌的错误。
答案 1 :(得分:23)
例如,考虑网卡的只读硬件寄存器。
它可能会在程序控制之外发生变化,因此不允许编译器将其值缓存在寄存器中或对其进行优化。因此,volatile
。
它是只读的,所以你不应该写它。因此,const
。
答案 2 :(得分:22)
首先,让我引用C11
标准的示例,章节§6.7.3,类型限定符
声明的对象
extern const volatile int real_time_clock;
可以由硬件修改,但不能分配,递增或递减。
此外,相关脚注(134),
易失性声明可用于描述与存储器映射的输入/输出端口或由异步中断功能访问的对象相对应的对象。对如此声明的对象的操作不应由实现“优化”或重新排序,除非评估表达式的规则允许。
这意味着,变量的值可以由硬件修改(通过内存映射),但不能“以编程方式”修改。
所以,这里的优势是双重的,
答案 3 :(得分:11)
我们可以使用文章Introduction to the volatile keyword来说明:
变量应该在其值可能发生变化时声明为volatile 不料。实际上,只有三种类型的变量可以改变:
- 内存映射外设寄存器
- 由中断服务程序修改的全局变量
- 多线程应用程序中的全局变量
和
嵌入式系统包含真正的硬件,通常是复杂的 外设。这些外设包含其值可能的寄存器 异步更改到程序流程。作为一个非常简单的例子, 考虑地址0x1234处的8位状态寄存器。这是必需的 您轮询状态寄存器,直到它变为非零。中殿 和不正确的实现如下:
UINT1 * ptr = (UINT1 *) 0x1234; // Wait for register to become non-zero. while (*ptr == 0); // Do something else.
一旦打开优化器,这几乎肯定会失败, 因为编译器将生成外观的汇编语言 像这样的东西:
mov ptr, #0x1234 mov a, @ptr loop bz loop
const表示你的程序不会改变变量,但正如文章中提到的那样,外部资源可以和volatile一起防止它被优化掉。
答案 4 :(得分:7)
* const volatile char * p =(const volatile char )0x30;
含义: p的值仅由外部条件改变。
从概念上讲,您可以将此类变量视为 逻辑查看器 。概念与门中的窥视孔相似。窥视孔允许您查看门另一侧的内容,但不允许您更改另一侧的内容( const )。但是,门外的条件可以根据自己的意愿改变(它们 volatile )。你可以看到会发生什么,但你不能改变发生的事情。
例如,在嵌入式系统中,有硬件寄存器,用于提供有关外部世界发生的事件的状态信息。例如,用于感测RPM的光学编码器将在寄存器中设置值。每次旋转,它都会感应来自LED的光并修改硬件寄存器中的值。这就是外部条件的含义。在图片的另一侧,即在您的代码中(可能是PID控制循环),您可以读取此信息以用于提供对循环的调整,但您不能更改此值,也不希望如此。 ( const )
从软件的角度来看,这说明了:
答案 5 :(得分:6)
const
不会使变量保持不变。它只是让编译器拒绝一些写访问。这仍然可以写入变量(例如通过常量指针)。
您可以将const
视为防止编码错误的保护。
此声明确保您不会无意中写入p
,同时告诉编译器不要优化访问(缓存,乱序执行(?),...),因为外部事件可能写入p
。