In a low level bare-metal embedded context, I would like to create a blank space in the memory, within a C++ structure and without any name, to forbid the user to access such memory location.
Right now, I have achieved it by putting an ugly uint32_t :96;
bitfield which will conveniently take the place of three words, but it will raise a warning from GCC (Bitfield too large to fit in uint32_t), which is pretty legitimate.
While it works fine, it is not very clean when you want to distribute a library with several hundreds of those warnings...
How do I do that properly?
The project I'm working on consists of defining the memory structure of different peripherals of a whole microcontroller line (STMicroelectronics STM32). To do so, the result is a class which contains a union of several structures which define all registers, depending on the targeted microcontroller.
One simple example for a pretty simple peripheral is the following: a General Purpose Input/Output (GPIO)
union
{
struct
{
GPIO_MAP0_MODER;
GPIO_MAP0_OTYPER;
GPIO_MAP0_OSPEEDR;
GPIO_MAP0_PUPDR;
GPIO_MAP0_IDR;
GPIO_MAP0_ODR;
GPIO_MAP0_BSRR;
GPIO_MAP0_LCKR;
GPIO_MAP0_AFR;
GPIO_MAP0_BRR;
GPIO_MAP0_ASCR;
};
struct
{
GPIO_MAP1_CRL;
GPIO_MAP1_CRH;
GPIO_MAP1_IDR;
GPIO_MAP1_ODR;
GPIO_MAP1_BSRR;
GPIO_MAP1_BRR;
GPIO_MAP1_LCKR;
uint32_t :32;
GPIO_MAP1_AFRL;
GPIO_MAP1_AFRH;
uint32_t :64;
};
struct
{
uint32_t :192;
GPIO_MAP2_BSRRL;
GPIO_MAP2_BSRRH;
uint32_t :160;
};
};
Where all GPIO_MAPx_YYY
is a macro, defined either as uint32_t :32
or the register type (a dedicated structure).
Here you see the uint32_t :192;
which works well, but it triggers a warning.
I might have replaced it by several uint32_t :32;
(6 here), but I have some extreme cases where I have uint32_t :1344;
(42) (among others). So I would rather not add about one hundred lines on top of 8k others, even though the structure generation is scripted.
The exact warning message is something like:
width of 'sool::ll::GPIO::<anonymous union>::<anonymous struct>::<anonymous>' exceeds its type
(I just love how shady it is).
I would rather not solve this by simply removing the warning, but the use of
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-WTheRightFlag"
/* My code */
#pragma GCC diagnostic pop
may be a solution... if I find TheRightFlag
. However, as pointed out in this thread, gcc/cp/class.c
with this sad code part:
warning_at (DECL_SOURCE_LOCATION (field), 0,
"width of %qD exceeds its type", field);
Which tells us that there is no -Wxxx
flag to remove this warning...
Use multiple adjacent anonymous bitfields. So instead of:
uint32_t :160;
for example, you'd have:
uint32_t :32;
uint32_t :32;
uint32_t :32;
uint32_t :32;
uint32_t :32;
One for each register you want to be anonymous.
If you have large spaces to fill it may be clearer and less error prone to use macros to repeat the single 32 bit space. For example, given:
#define REPEAT_2(a) a a
#define REPEAT_4(a) REPEAT_2(a) REPEAT_2(a)
#define REPEAT_8(a) REPEAT_4(a) REPEAT_4(a)
#define REPEAT_16(a) REPEAT_8(a) REPEAT_8(a)
#define REPEAT_32(a) REPEAT_16(a) REPEAT_16(a)
Then a 1344 (42 * 32 bit) space can be added thus:
struct
{
...
REPEAT_32(uint32_t :32;)
REPEAT_8(uint32_t :32;)
REPEAT_2(uint32_t :32;)
...
};