Search code examples
cvolatile

Volatile access of struct member


If accessing a struct member marked as volatile from an interrupt, does the whole chain of access need to be marked as volatile ?

For example

struct bar
{
  volatile uint16_t a;
  volatile uint16_t b;
};

struct foo
{
  struct bar bar1;
  struct bar bar2;
};

struct foo foo_arr[10];

void interrupt_handler(void)
{
  struct bar *bar = &foo_arr[0].bar1;
  bar->a = 2;
  bar->b = 3;
}

Will it be enough for the members a and b to marked as volatile ?


Solution

  • Normally, it is often problematic to specify qualifiers on individual struct members rather than on the struct object. In this case, since every single member is volatile, you could as well have done volatile struct bar bar1, allowing non-volatile instances of the struct to exist as well.

    However, in case a and b happens to be memory-mapped CPU registers, there exists no situation where they aren't volatile so by qualifying the individual members as such, you prevent any other use of them which is a good thing in that particular scenario. There would be no harm of making the struct volatile as well though.


    As for the use of these variables, the only thing that matters is the type used for the "lvalue access" of the member object, which must be done through a correctly qualified type. For example * (int*)&bar->a would invoke undefined behavior - same thing if you used const in the declaration.

    A compiler can't assume anything about this struct either, it must treat it as volatile all the way. It would however have been much clearer and self-documenting to the programmer if it was explicitly declared volatile at every turn. Not declaring something volatile when the intention is to treat it as volatile is simply bad programming style. But as far as the C language cares, that's not necessary.

    You can easily test this: https://godbolt.org/z/rxqPe8abx Comment out volatile and the (x86_64 port) compiler optimizes the writes into a single 32 bit write, which wouldn't be conforming for 2 volatile variables. With volatile we do get 2 separate 16 bit writes, which is required by C's rules of program execution ("the abstract machine").