3

I'm running C on an embedded system and I want to make sure that the value of a certain #define is equal to a specific value. If not, I want the compiler to fail and not proceed.

My code currently looks like this:

typedef uint32_t TickType_t; //I can NOT change/modify this typedef
#define configTICK_RATE_HZ  ( ( TickType_t ) 1000 ) //I can NOT change/modify this macro, it's autogenerated

I'm then trying to do the following in my code:

#if(1000 != configTICK_RATE_HZ)
    #error "configTICK_RATE_HZ is not 1000Hz!"
#endif

I run into an error during the build because the #if doesn't like seeing that typecast (compilers don't know typedefs). I found a stackoverflow discussion about how to strip/remove the typecast (link) with a very creative answer but it's not quite working for me yet because I think I need to remove the outmost parenthesis from the original macro first before using that creative solution.

Asked another way, I want the preprocessor output of this:

#if(1000 != configTICK_RATE_HZ )

To look like this: #if(1000 != 1000)

And not like this: #if(1000 != ( ( TickType_t ) 1000 ) )

I don't mind intermediate macros if needed, but I can not change the original "configTICK_RATE_HZ" definition or the typedef of TickType_t

Here's some minimal reproducible code (a similar problem that covers the same issue that I'm running into). The code below fails because it doesn't like the typecast or the outmost parenthesis in that macro.

#include <stdio.h>
#define FREQ_HZ ((int)10) //Can not modify this definition

#if( 10 != FREQ_HZ )
#error "Bad frequency value"
#endif

int main(void)
{
    printf("Hello world\n");
}

1 Answers1

3

You can't use the preprocessor for this, but you can use a static assertion.

The static_assert declaration allows for a constant expression to be checked at compile time and generate an error with the given text if the condition is false.

static_assert(1000 == configTICK_RATE_HZ, "configTICK_RATE_HZ is not 1000Hz!");
dbush
  • 205,898
  • 23
  • 218
  • 273
  • It would really be useful to be able to do this at compilation time not during run-time. All I really need is some macro magic that can strip the outer parenthesis from the original definition. Removing the typecast afterwards should be easy – AamerAirlines Apr 05 '23 at 17:52
  • @AamerAirlines This does happen at compilation time. That's what a `static_assert` is for. If the condition is false, the compiler will generate an error which includes the given text. – dbush Apr 05 '23 at 18:00
  • Hi @dbush, sorry for the confusion. I believe you are correct (static_assert does execute during compilation time). I ran into an error when I tried to use it initially which is why I thought it worked only during runtime. That being said, I needed to tweak your suggestion a bit to get it to do what I needed for me: `_Static_assert(1000 == configTICK_RATE_HZ, "configTICK_RATE_HZ is not 1000Hz!");` – AamerAirlines Apr 05 '23 at 18:17
  • @AamerAirlines Yes, I had the condition inverted, and `static_assert` is a macro for `_Static_assert`. That macro should be available if you `#include ` – dbush Apr 05 '23 at 18:21
  • thank you! That was it, I just needed to `#include ` to get `static_assert` to work. I do notice some minor odd behavior: When the condition fails (e.g. configTICK_RATE_HZ is not 1000), compiler fails but it doesn't print the desired error message. Instead it shows a different error: "the size of an array must be greater than zero". This is minor and not an issue for me, so I don't care much to fix it. – AamerAirlines Apr 05 '23 at 18:26
  • Note that `static_assert` will become a proper keyword in C23 and the string literal argument will become optional. – Lundin Apr 06 '23 at 06:30