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.