C variable type assert

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


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 :-)


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;
  }
}

Tags:

C