How do I check if a variable is of a certain type (compare two types) in C?

Getting the type of a variable is, as of now, possible in C11 with the _Generic generic selection. It works at compile-time.

The syntax is a bit like that for switch. Here's a sample (from this answer):

    #define typename(x) _Generic((x),                                                 \
            _Bool: "_Bool",                  unsigned char: "unsigned char",          \
             char: "char",                     signed char: "signed char",            \
        short int: "short int",         unsigned short int: "unsigned short int",     \
              int: "int",                     unsigned int: "unsigned int",           \
         long int: "long int",           unsigned long int: "unsigned long int",      \
    long long int: "long long int", unsigned long long int: "unsigned long long int", \
            float: "float",                         double: "double",                 \
      long double: "long double",                   char *: "pointer to char",        \
           void *: "pointer to void",                int *: "pointer to int",         \
          default: "other")

To actually use it for compile-time manual type checking, you can define an enum with all of the types you expect, something like this:

    enum t_typename {
        TYPENAME_BOOL,
        TYPENAME_UNSIGNED_CHAR,
        TYPENAME_CHAR,
        TYPENAME_SIGNED_CHAR,
        TYPENAME_SHORT_INT,
        TYPENAME_UNSIGNED_CHORT_INT,
        TYPENAME_INT,
        /* ... */
        TYPENAME_POINTER_TO_INT,
        TYPENAME_OTHER
    };

And then use _Generic to match types to this enum:

    #define typename(x) _Generic((x),                                                       \
            _Bool: TYPENAME_BOOL,           unsigned char: TYPENAME_UNSIGNED_CHAR,          \
             char: TYPENAME_CHAR,             signed char: TYPENAME_SIGNED_CHAR,            \
        short int: TYPENAME_SHORT_INT, unsigned short int: TYPENAME_UNSIGNED_SHORT_INT,     \
              int: TYPENAME_INT,                     \
        /* ... */                                    \
            int *: TYPENAME_POINTER_TO_INT,          \
          default: TYPENAME_OTHER)

C does not support this form of type introspection. What you are asking is not possible in C (at least without compiler-specific extensions; it would be possible in C++, however).

In general, with C you're expected to know the types of your variable. Since every function has concrete types for its parameters (except for varargs, I suppose), you don't need to check in the function body. The only remaining case I can see is in a macro body, and, well, C macros aren't really all that powerful.

Further, note that C does not retain any type information into runtime. This means that, even if, hypothetically, there was a type comparison extension, it would only work properly when the types are known at compile time (ie, it wouldn't work to test whether two void * point to the same type of data).

As for typeof: First, typeof is a GCC extension. It is not a standard part of C. It's typically used to write macros that only evaluate their arguments once, eg (from the GCC manual):

 #define max(a,b) \
   ({ typeof (a) _a = (a); \
      typeof (b) _b = (b); \
     _a > _b ? _a : _b; })

The typeof keyword lets the macro define a local temporary to save the values of its arguments, allowing them to be evaluated only once.

In short, C does not support overloading; you'll just have to make a func_a(struct a *) and func_b(struct b *), and call the correct one. Alternately, you could make your own introspection system:

struct my_header {
  int type;
};

#define TYPE_A 0
#define TYPE_B 1

struct a {
  struct my_header header;
  /* ... */
};

struct b {
  struct my_header header;
  /* ... */
};

void func_a(struct a *p);
void func_b(struct b *p);

void func_switch(struct my_header *head);
#define func(p) func_switch( &(p)->header )

void func_switch(struct my_header *head) {
  switch (head->type) {
    case TYPE_A: func_a((struct a *)head); break;
    case TYPE_B: func_b((struct b *)head); break;
    default: assert( ("UNREACHABLE", 0) );
  }
}

You must, of course, remember to initialize the header properly when creating these objects.


Gnu GCC has a builtin function for comparing types __builtin_types_compatible_p.

https://gcc.gnu.org/onlinedocs/gcc-3.4.5/gcc/Other-Builtins.html

This built-in function returns 1 if the unqualified versions of the types type1 and type2 (which are types, not expressions) are compatible, 0 otherwise. The result of this built-in function can be used in integer constant expressions.

This built-in function ignores top level qualifiers (e.g., const, volatile). For example, int is equivalent to const int.

Used in your example:

double doubleVar;
if(__builtin_types_compatible_p(typeof(doubleVar), double)) {
    printf("doubleVar is of type double!");
}

As other people have already said this isn't supported in the C language. You could however check the size of a variable using the sizeof() function. This may help you determine if two variables can store the same type of data.

Before you do that, read the comments below.

Tags:

C

Types

Struct