Read-only memory-mapped registers defined with `volatile const` in C but only `volatile` in C++

c, c++, cmsis, embedded

Solution

Because no `RoReg` object is ever instantiated, there is no good reason to omit the `const` qualifier in the typedef.

Every use of `RoReg` is in either a macro that defines a pointer to the type...

#define REG_WDT_SR (*(RoReg*)0x400E1A58U) /**< \brief (WDT) Status Register */

...or a `struct` declaration that is accessed using a similar macro.

typedef struct {
  WoReg WDT_CR; /**< \brief (Wdt Offset: 0x00) Control Register */
  RwReg WDT_MR; /**< \brief (Wdt Offset: 0x04) Mode Register */
  RoReg WDT_SR; /**< \brief (Wdt Offset: 0x08) Status Register */
} Wdt;

#define WDT        ((Wdt    *)0x400E1A50U) /**< \brief (WDT) Base Address */

Even with the `const` qualifier, the code should behave the same in both C and C++.

Perhaps the author misinterpreted the standard. To guarantee that a C++ struct has the same layout as in C, it requires that the class "has the same access control (Clause 11) for all non-static data members." The author may have mistaken `const` and `volatile` for access control specifiers. If they were, then you would want all the struct members to have the same cv-qualifiers in order to ensure compatibility between the C and C++ (and hardware) layouts. But it's `public`, `protected`, and `private` that define access control.

Problem

While working on an embedded systems project using an Atmel SAM3X8E, I noticed the following bit of code in some of the CMSIS header files. ``` #ifndef __cplusplus typedef volatile const uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */ #else typedef volatile uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */ #endif ``` Why does the typedef for C++ not include `const`? I saw somewhere a mention that C++ does not store integer const variables in runtime memory, which if true would mean the `const` would need to be removed because of how microcontroller registers are memory-mapped, but I can't seem to find anything else saying that C++ does that (though my search was admittedly pretty brief). Not having much experience with C++, I also thought it might be that C++ doesn't allow `const` struct members, as those typedefs are mostly used in struct typedefs for collections of registers, but that doesn't seem to be the case either.

Original source