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\'
I know the issue thread is old, however I encountered it today... If you do not want to or cannot change the #define, the other answers are great, but if you have access to the #define, I recommend using for pre-processor operations (#if - #else - #endif) instead of:
#define FLASH_BLOCK_SIZE ((uint8_t)64)
use this define:
#define FLASH_BLOCK_SIZE (64U)
This way the cast is still there, and the compiler won't be "confused".
After macro replacement, a preprocessor expression may have subexpressions of the form defined identifier
or defined ( identifier )
. Other than that, identifiers and keywords have no meaning; each identifier or keyword is replaced by 0
. So this:
#if 64 != ((uint8_t)64)
is equivalent to this:
#if 64 != ((0)64)
which is a syntax error. The fact that it's a typedef
isn't the problem; a keyword like int
gets the same treatment.
So given:
#define FLASH_BLOCK_SIZE ((uint8_t)64)
you can't use FLASH_BLOCK_SIZE
in a preprocessor expression.
The best solution I can think of is to change your definition:
#define FLASH_BLOCK_SIZE_NUM 64
#define FLASH_BLOCK_SIZE ((uint8_t)FLASH_BLOCK_SIZE_NUM)
You can then use FLASH_BLOCK_SIZE_NUM
in preprocessor expressions and FLASH_BLOCK_SIZE
elsewhere.
On the other hand, do you really need the (int8_t)
cast in the first place? Arithmetic expressions are implicitly converted in many contexts, usually to the appropriate type. In many contexts, (uint8_t)
will be promoted to int
anyway. It's very likely you can just drop the cast and use:
#define FLASH_BLOCK_SIZE 64
To be sure, you'll need to examine all the code that refers to FLASH_BLOCK_SIZE
. (Evaluating sizeof FLASH_BLOCK_SIZE
would be a problem, but I'm betting you never do that.)
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.
For any typedef you can get arrount this by changing to
#define FLASH_BLOCK_SIZE ((uint8_t)+64)
notice the little plus in there?
The preprocessor replaces the typename it doesn't know anything about by 0, so this works out in both contexts. (The preprocessor is supposed to do all arithmetic in [u]intmax_t
, anyhow)
For the actual type you are using all of this makes not much sense. There is no such thing as a uint8_t
constant. As soon they are evaluated all expressions of a type that is narrower than int
are converted to int
. So it probably doesn't makes any difference.
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 embeffffded C compiler support C11.