3 ms·
This is actually more subtle than one would think. Say you were trying to talk to three UART registers at 0xA000, 0xA004, and 0xA008. It's legal to access:
by nrclark 7y ago
This is actually more subtle than one would think.
Say you were trying to talk to three UART registers at 0xA000, 0xA004, and 0xA008. It's legal to access:
*(volatile uint32_t *)(0xA000);
*(volatile uint32_t *)(0xA004);
*(volatile uint32_t *)(0xA008);
The struct equivalent of this would be something like:
struct UART_Peripheral {
volatile uint32_t control;
volatile uint32_t txdata;
volatile uint32_t rxdata;
};
struct UART_Peripheral *uart0 = 0xA000;
uart0->control;
uart0->txdata;
uart0->txdata;
As long as your structure is packed/aligned correctly, this is perfectly valid C. You can enforce the structure packing with an __attribute__ ((__packed__)) if using GCC or Clang. I think MSVC has a pragma for it.
I know that the C language spec allows for structure padding, but I'm not sure if the concept is applicable if every member of the structure is the native word-size of the target CPU.
But regardless of whether the spec specifies this expicitly or not, I've never seen a compiler insert padding in-between struct members that are already word-aligned.
So the code might be very slightly questionable if written in pure C with no packing pragmas/attributes - but even then it would probably work on almost every target. And if used with the right pragma/attribute for your compiler, it's a perfectly valid construct. And it's also a common one - especially in embedded work or hardware drivers.
- chrisseaton 7y agoThe C standard doesn't define what happens when you cast an integer to a pointer like that. For example I work with a compliant C implementation where this would not work, because it uses fat pointers.
- nrclark 7y agoInteresting! I didn't know that. Does uintptr_t exist on your platform? If so, how does it work?