In a microcontroller code, I am using a library provided by the producer where there are many constants defined. I'm trying to give an error if there's a mismatch between some of my constants (shared with components outside the microcontroller, with git-subtree
) and the microcontroller constants.
For example, the library defines:
#ifdef SOME_PARTICULAR_MODEL
#define FLASH_BLOCK_SIZE ((uint8_t)64)
/* else, other models */
#endif
And somewhere, in a header shared between the microcontroller code and some code compiled on the PC, I have for example:
#define MYPROG_BLOCK_SIZE 64
And to make sure these constants match, in the microcontroller code, where both constants exist, I have:
#if MYPROG_BLOCK_SIZE != FLASH_BLOCK_SIZE
#error "mismatch between actual block size and defined block size"
#endif
This is to make sure if the code is ever ported to a bigger microcontroller, the shared header would also be updated.
The problem is that this gets reduced to:
#if 64 != ((uint8_t)64)
which I'm not sure if is valid C, but nonetheless makes the compiler choke up. Testing, I found out that the problem is not that uint8_t
is a typedef and it still chokes up with a cast to int
for example.
Is there a way to remove the (uint8_t)
part from a value defined as ((uint8_t)64)
? If not, is there any way to change it so the expression turns into one without a cast?
I thought about defining uint8_t
as something and undefining it after the #if
, but I can't figure out how I can avoid the cast nature of (Y)X
and turn it into an arithmetic expression.
Here is an improved version (the first version is below). This one does not depend on the cast being uint8_t
; it will work with any FLASH_BLOCK_SIZE
replacement list of the form ((some type) number)
.
#define MYPROG_BLOCK_SIZE 64
#define FLASH_BLOCK_SIZE ((uint8_t)64)
#define B(x)
#define C(x) B x
#define D(x) C x
#if MYPROG_BLOCK_SIZE != D(FLASH_BLOCK_SIZE)
#error "mismatch between actual block size and defined block size"
#endif
This works:
D(FLASH_BLOCK_SIZE)
, FLASH_BLOCK_SIZE
is replaced by ((uint8_t) 64)
, effectively making D(((uint8_t) 64))
.D(((uint8_t) 64))
is replaced by C ((uint8_t) 64)
.C
macro, which replaces C(x)
with B x
, so C ((uint8_t) 64)
is replaced by B (uint8_t) 64
.B (uint8_t)
invokes the B
macro, which has an empty replacement list, so B (uint8_t) 64
becomes 64
.Here is the original version:
#define MYPROG_BLOCK_SIZE 64
#define FLASH_BLOCK_SIZE ((uint8_t)64)
#define uint8_t
#define Helper(x) x
#define Deparenthesize(x) Helper x
#if MYPROG_BLOCK_SIZE != Deparenthesize(Deparenthesize(FLASH_BLOCK_SIZE))
#error "mismatch between actual block size and defined block size"
#endif
#undef uint8_t
When writing code, I would prefer a static assert, but the above does what you requested in the preprocessor.