具有易失性和外部数据访问的 C++ 常量正确性
Posted
技术标签:
【中文标题】具有易失性和外部数据访问的 C++ 常量正确性【英文标题】:C++ Const-correctness with volatile and external data acess 【发布时间】:2013-07-22 14:23:30 【问题描述】:我是一名嵌入式 C 开发人员,最近开始在嵌入式设备上处理 C++ 代码,我不确定当类访问易失性数据(例如内存映射寄存器或外部设备上的数据)时如何应用 const 正确性,例如模数转换器 (ADC)。
例如,我有一些类通过指针访问设备的内存映射寄存器来连接设备的硬件模块,如下所示:
class IOPin
public:
/* Constructor, destructor, other methods...*/
// should this be a const method?
bool Readiostate() return portregs_->state;
private:
/* Other private stuff...*/
// Constructor points this to the right set of memory-mapped registers
volatile struct portregs_t
uint32_t control;
uint32_t state;
uint32_t someotherreg;
*portregs_;
;
寄存器名称当然是为了举例而编造的。我正在为任何好奇的人使用 Microchip PIC32 设备。
根据我可能不正确的理解,标记方法const
意味着就调用者而言,对象的可观察状态不应改变。那么ReadIOState()
方法不是否应该是const
,因为它访问的volatile
数据可能随时更改,因此调用者会观察到更改?还是应该是 const
,因为 方法 没有明确改变任何东西?
目前,由于问题中所述的原因,我倾向于不使用该方法const
。在偶然发现this GotW article 之后尤其如此,它指出const
的含义正在更改为“能够同时读取”。我的嵌入式应用程序是单线程的,但我想这可能是对const
ness 的一个很好的试金石。
另外,编译器如何处理const
方法?也就是说,当我想像这样轮询 IO 的状态时会发生什么:
// wait for IO pin to go high
while(!myIOpin.ReadIOState())
如果ReadIOState()
是const
,那么编译器是否可以重用一次调用后返回的值,或者它是否足够聪明地看到它正在访问volatile
数据而不这样做?
【问题讨论】:
我想知道你是否可以像创建 const 方法一样创建 volatile 方法。 void test() volatile 在 VS2012 上编译,但我不知道这是什么意思,因为我以前从未使用过 volatile。 @NeilKirk 是的,你可以做到。这意味着可以在volatile
实例上调用该函数。就像const
函数可以在const
实例上调用一样。如果您愿意,您甚至可以拥有成员函数的所有 4 个重载。
这些 cmets 让我意识到我必须考虑如何在中断例程中使用 C++ 对象。其中使用的变量通常被声明为 volatile,尽管我不确定这如何应用于我正在调用其方法而不是直接访问成员的对象。
【参考方案1】:
你只是有指向类内部结构的指针,你没有改变指针,所以方法可以是 const。编译器不应该重用之前调用的值,它已经足够聪明了。
【讨论】:
感谢您的回复!这是真的,我一直不得不提醒自己,指针本身就是常量。但是,我认为我的问题更多的是哲学方面的。也就是说,对方法使用 const 是否意味着该方法的返回值?如果返回值可以在对方法的两次连续调用之间发生变化,即使该类不是更改它们的类,那么说它是 const 是否有意义? Const 是一个仅在编译时使用的关键字,在运行时不执行与 const 相关的特殊检查(仅在运气好且 const 值存储在只读内存页的情况下OS),该关键字仅用于在编译时从编译器获得更多帮助(编译错误)。对方法使用 const 并不意味着方法的返回值。这是 C++ 不太直观的一面。以上是关于具有易失性和外部数据访问的 C++ 常量正确性的主要内容,如果未能解决你的问题,请参考以下文章
对具有“易失性”属性的动态分配变量的内存访问是不是会导致每次访问的缓存未命中?
CYPRESS代理64Kbit非易失性铁电存储器FM25640B