For some devices, reading a register might have side effects.
For example, I/O memory:
I/O memory is simply a region of RAM-like locations that the device makes available to the processor over the bus. This memory can be used for a number of purposes, such as holding video data or Ethernet packets, as well as implementing device registers that behave just like I/O ports (i.e., they have side effects associated with reading and writing them).
The following line is probably meant to activate some kind of side effect on this device:
(void)NRF_RADIO->EVENTS_END;
Sometimes you will just want to read the data back from the register to make the CPU wait for the data to be written.
However just reading the data without using it might make the compiler issue a warning and will eventually remove this statement completely if optimization is used (as shown below)
Solution (edited thanks to the comments below)
- Adding a cast to void assert the compiler that you know what you are doing and will not issue a warning.
- To avoid removing this statement from the program, the fields in the struct should also be volatile.
For example
To demonstrate how adding/removing (void)/volatile from your code might affect the produced code, I'll show here a few examples.
Note: The following examples are undefined behavior for C/C++, but are well defined under gcc + x86.
The following program will produce a warning, but running it will not produce segmentation fault because the pointer will never be read (the compiler will consider it redundant).
struct example {
int b;
};
int main() {
struct example * a = NULL;
a->b;
return 0;
}
The following program will produce a warning, but running it will produce segmentation fault due to the use of volatile. Although the compiler is aware that this location needs to be used directly, thus it cannot know what side effects it might have.
struct example {
volatile int b;
};
int main() {
struct example * a = NULL;
a->b;
return 0;
}
The following program will not produce any warning, but running it will produce a segmentation fault.
struct example {
volatile int b;
};
int main() {
struct example * a = NULL;
(void)a->b;
return 0;
}
The following program will not produce any warning, and running it will not produce a segmentation fault.
struct example {
int b;
};
int main() {
struct example * a = NULL;
(void)a->b;
return 0;
}