ctypesstruct

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


In C (not C++/C#) how do I check if a variable is of a certain type?

For example, something like this:

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

Or more general: How do I compare two types so that compare(double1,double2) will evaluate to true, and compare(int,double) will evaluate to false. Also I'd like to compare structs of different composition as well.

Basically, I have a function that operates on variables of type "struct a" and "struct b". I want to do one thing with the "struct a" variables and the other with the "struct b" variables. Since C doesn't support overloading and the void pointer losses its type information I need to check for type. BTW, what would be the sense in having a typeof operator, if you can't compare types?


The sizeof method seems to be a practical workaround solution for me. Thanks for your help. I still find it a bit strange since the types are known at compile time, but if I imagine the processes in the machine I can see, why the information is not stored in terms of types, but rather in terms of byte size. Size is the only thing really relevant besides addresses.


Solution

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