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.
This is called token pasting or token concatenation. The ' ## ' preprocessing operator performs token pasting.
The preprocessor defined operator is used in constant expressions to determine if an identifier is defined using #define. If the specified identifier is defined, the value is true (non-zero). If the symbol is not defined, the value is false (zero). The defined operator is specified as follows − #include <stdio.h> #if !
We can create two or more than two strings in macro, then simply write them one after another to convert them into a concatenated string. The syntax is like below: #define STR1 "str1" #define STR2 " str2" #define STR3 STR1 STR2 //it will concatenate str1 and str2. Input: Take two strings.
For ans [A]. #define is a preprocessor directive.
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
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.
The solution is to use static assert. With a good STATIC_ASSERT
macro, you can put a static assert at file-scope in your header file:
STATIC_ASSERT(FLASH_BLOCK_SIZE == MYPROG_BLOCK_SIZE);
Here is an exemple of definition for the STATIC_ASSERT
macro:
#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x ## y
#define STATIC_ASSERT(expr) \
extern int CAT(static_assert_failed_, __LINE__)[(expr) ? 1 : -1]
With some compilers (e.g., IAR), you have static_assert
as a compiler builtin. static_assert
is also present in C11 but unfortunately not a lot of embeddded C compiler support C11.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With