15
uint32_t fail_count = 0;

...

if(is_failed)
    if(fail_count < UINT32_MAX - 1 )
        ++fail_count;

It works fine, but this code is fragile. Tomorrow, I may change the type of fail_count from uint32_t to int32_t and I forget to update UINT32_MAX.

Is there any way to assert fail_count is a uint32_t at the function where I have written my ifs?

P.S. 1- I know it is easy in C++ but I'm looking for a C way.

P.S. 2- I prefer to use two asserts than relying on the compiler warnings. Checking the number size via sizeof should work but is there any way to distinguish if type is unsigned?

  • I don't think so. C doesn't have any type introspection mechanisms. – Barmar Apr 23 at 4:06
  • You could use macros to define your types, and the macro could create two variables. – Barmar Apr 23 at 4:07
  • 2
    A decent compiler will warn of the comparison fail_count < UINT32_MAX - 1 if fail_count is int32_t as the comparison will always be true. (as well as a comparison between signed and unsigned types) – David C. Rankin Apr 23 at 4:07
  • you want it for any specific compiler or in general? – P.W Apr 23 at 4:09
  • @P.W a specific embedded device compiler. But I look for a robust code that works on both IAR and GCC. – alex Apr 23 at 4:11
22

As of C11, you can use a generic selection macro to produce a result based on the type of an expression. You can use the result in a static assertion:

#define IS_UINT32(N) _Generic((N), \
  uint32_t: 1, \
  default: 0 \
)

int main(void) {
  uint32_t fail_count = 0;
  _Static_assert(IS_UINT32(fail_count), "wrong type for fail_count");
}

You could of course use the result in a regular assert(), but _Static_assert will fail at compile time.

A better approach could be dispatching the comparison based on type, again using generic selection:

#include <limits.h>
#include <stdint.h>

#define UNDER_LIMIT(N) ((N) < _Generic((N), \
int32_t: INT32_MAX, \
uint32_t: UINT32_MAX \
) -1)

int main(void) {
  int32_t fail_count = 0;

  if (UNDER_LIMIT(fail_count)) {
    ++fail_count;
  }
}
1

As you mentioned GCC, you can use a compiler extension to accomplish this in case you are not using C11:

First write a macro that emulates the C++ is_same. And then call it with the types you want to compare.

A minimal example for your particular case:

#include<assert.h>

#define is_same(a, b) \
  static_assert(__builtin_types_compatible_p(typeof(a), typeof(b)), #a " is not unsigned int")

int main()
{
    int fail_count = 0;    
    is_same(fail_count, unsigned int);
}

The compiler asserts:

<source>: In function 'main':
<source>:4:3: error: static assertion failed: "fail_count is not unsigned int"
   static_assert(__builtin_types_compatible_p(typeof(a), typeof(b)), #a " is not unsigned int")
   ^~~~~~~~~~~~~

<source>:9:5: note: in expansion of macro 'is_same'
     is_same(fail_count, unsigned int);
 ^~~~~~~

See Demo

  • Weird. OP even explicitly answer your question about compilers with "a specific embedded device compiler", not gcc. OP even mentions it should work on IAR too. Still you give a gcc-only answer. – pipe Apr 23 at 9:36
  • 3
    Actually when I wrote the comment, I was about to write the same answer as Ryan but he wrote it a few minutes before me. So there was no point writing the same again. Also remember that the answers on this site are not just for the OP. What if someone who is still using C99 want to accomplish this task with GCC? So nothing weird about this. – P.W Apr 23 at 9:47
1

What about a low-tech solution that works even with K&R C and any compiler past and present?

Place the right comment in the right place:

/*
 * If this type is changed, don't forget to change the macro in
 * if (fail_count < UINT32_MAX - 1) below (or file foobar.c)
 */
uint32_t fail_count = 0;

With a proper encapsulation this should refer to exactly one place in the code. Don't tell me you increment the fail count in many places. And if you do, what about a

#define FAIL_COUNT_MAX  UINT32_MAX

right next to the declaration? That's more proper and clean code anyway. No need for all the assertion magic and rocket sciencery :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.