in core_cm4.h header file defined some thing like this:

#ifdef __cplusplus
  #define   __I     volatile             /*!< Defines 'read only' permissions                 */
  #define   __I     volatile const       /*!< Defines 'read only' permissions                 */
#define     __O     volatile             /*!< Defines 'write only' permissions                */
#define     __IO    volatile             /*!< Defines 'read / write' permissions              */

What's the difference between __I , __O and __IO while they are defined in same way.

  • and how they work to specify "read/write only" while they are only defined as a volatile variable ?!
  • 2
    \$\begingroup\$ Naming convention? I think the keyword you're looking for is "volatile const". \$\endgroup\$
    – Long Pham
    Commented Oct 15, 2018 at 15:17

3 Answers 3


"I" means: Input

"O" means: Output

"IO" means: Input and Output

As Long Pham notes, it is a naming convention, but also it is normal to use meanings to a type. Like an integer can be a counter, a timestamp, a date etc.

There are some reasons to use this:

  • It is good for readability
  • Whenever in future the type of an I, O or IO would change, (user) source code using I, O and IO does not need to be changed, only the type definitions / defines itself.
  • 1
    \$\begingroup\$ Doesn't explain why they use a different C++ compiler switch though. I think the limits of C++ is the main reason why they invented these home-brewed qualifiers to begin with. \$\endgroup\$
    – Lundin
    Commented Jul 2, 2020 at 13:48
  • \$\begingroup\$ @Lundin I think so too, I focused on the I/O/IO differences regarding naming \$\endgroup\$ Commented Jul 2, 2020 at 13:55

Since this is for the definition of a hardware register map:

I think the reason is that C, unlike C++, allows the declaration of const qualified variables without providing an initializer:

volatile const uint32_t REG; // Ok in C, invalid in C++

Similarly, C++ doesn't allow const members of struct/classes to be uninitialized either. This is inconvenient when we have read-only hardware registers and wish to make a register map by using structs (classes).

This C++ language limitation is likely why this header uses a dirty hack #ifdef __cplusplus to remove const from a register that should have been const qualified.

  • \$\begingroup\$ Just one of many small details making C++ less suitable than C for hardware-related programming. \$\endgroup\$
    – Lundin
    Commented Jul 2, 2020 at 13:46

This header file was created to support the c++ as well,

Hence in case of C const variable denoted constant and cannot be modified by the user,However there is no any further optimization for this const variable by the C compiler.

But in case of C++ ,this const variable can be replaced by the constant value assigned to that variable.

In case of c++ structure member variables are not optimized hence const can be used there.

Therefore, this header file provides __I ,__O , __IO for the scalar variables and
__IM ,__OM ,__IOM for the structure members.

  • \$\begingroup\$ I neither understand nor agree with this explanation. What do you mean "no further optimization"? That's no specified by any standard, compilers may do as they please. And what on earth does that have to do with register maps? I sure hope that some nutty C++ compiler doesn't replace my read-only hardware register variable with an integer constant. \$\endgroup\$
    – Lundin
    Commented Jul 2, 2020 at 13:44
  • \$\begingroup\$ @Lundin "no further optimization means" in C the 'const' variable will be treated as a variable whose value cannot be modified in code by the user and in the background, it won't be replaced by its value directly into the code. Each read operation will access the variable's address for its value. In this case, the compiler will allocate memory for this variable in the Text section. \$\endgroup\$ Commented Apr 25, 2021 at 6:38
  • \$\begingroup\$ @Lundin Register maps have to be defined with 'Volatile' and 'const' according to the type of the register, For example, let's say we have an ADC Conversion output register which I have mapped to a variable. Now for a better, robust and bug-free program, we want the variable to be read-only so that it won't be accidentally written. Hence const help us here. And we also want each read operation should go deep down and get the value from the memory location, not from the read/write buffer(this may occur in case of high optimization setting during compilation) Hence volatile helps in this case. \$\endgroup\$ Commented Apr 25, 2021 at 6:53
  • \$\begingroup\$ @Lundin you can refer developer.arm.com/documentation/ka002980/latest \$\endgroup\$ Commented Apr 25, 2021 at 6:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.