很抱歉,如果这很简单,我的C ++就生锈了。
这是做什么的?据我所知,没有任何分配或函数调用。在我继承的一些代码中,这个代码模式重复了很多次。如果重要的是它的嵌入代码。
*(volatile UINT16 *)&someVar->something;
编辑:从那里开始,以下附加代码是否确认了希思的怀疑? (完全来自代码,包括重复,除了名称已被更改以保护无辜者)
if (!WaitForNotBusy(50))
return ERROR_CODE_X;
*(volatile UINT16 *)& someVar->something;
if (!WaitForNotBusy(50))
return ERROR_CODE_X;
*(volatile UINT16 *)& someVar->something;
x = SomeData;
答案 0 :(得分:19)
这是嵌入式编程中相当常见的习惯用法(尽管它应该封装在一组函数或宏中),其中需要访问设备寄存器。在许多体系结构中,设备寄存器被映射到存储器地址,并且像任何其他变量一样被访问(尽管在固定地址处 - 可以使用指针,或者链接器或编译器扩展可以帮助修复地址)。但是,如果C编译器没有看到对变量访问的副作用,它可以将其优化 - 除非变量(或用于访问变量的指针)被标记为volatile。
所以表达;
*(volatile UINT16 *)&someVar->something;
将从something
指针中存储的地址以某个偏移量(由someVar
结构元素的偏移量提供)发出16位读取。由于volatile
关键字,编译器将无法进行此读取。
请注意,某些器件寄存器即使只是读取它们也会执行某些功能 - 即使没有使用其他数据也是如此。这在状态寄存器中非常常见,其中在读取指示特定位中的错误状态的寄存器之后可能会清除错误条件。
这可能是使用volatile
关键字的常见原因之一。
答案 1 :(得分:9)
我认为作者的意图是让编译器在这些点发出内存障碍。通过评估 volatile 的表达式结果,对编译器的指示是该表达式不应该被优化掉,并且应该“实例化”访问易失性位置的语义(内存障碍,对优化)在这个习语出现的每一行。
这种类型的习惯用法可以“封装”在预处理器宏(#define
)中,以防另一个编译具有不同的方式来产生相同的效果。例如,具有直接编码读取或写入内存屏障能力的编译器可能使用内置机制而不是此习惯用法。在宏中实现这种类型的代码可以在整个代码库中更改方法。
编辑:如果此代码在指针的地址是物理而不是虚拟地址(或虚拟)的环境中运行,那么用户就可以了。映射到特定物理地址的地址),然后执行此读取操作可能会导致外围设备执行某些操作。
答案 2 :(得分:9)
所以这是一个很长的镜头。
如果该地址指向FPGA或其他设备上的内存映射区域,那么当您读取该地址时,该设备可能实际上正在执行某些操作。
答案 3 :(得分:-1)
通常这是错误的代码。
在C和C ++中,volatile意味着很少,并且不提供隐式内存屏障。所以这段代码完全错了,你写的是
memory_barrier();
*(volatile UINT16 *)&someVar->something;
这只是糟糕的代码。
费用: volatile
不会使变量成为原子!
Reed this article:http://www.mjmwired.net/kernel/Documentation/volatile-considered-harmful.txt
这就是volatile
几乎永远不会在正确的代码中使用的原因。