Of course! In C, there isn't a direct, built-in keyword like typeof that you can use in the same way you might in C++ or other languages. However, there are several ways to achieve similar functionality, ranging from compiler-specific extensions to modern standard C features.

Let's break down the methods, from the most common to the most modern.
The Most Common Method: sizeof(type)
While sizeof doesn't give you the type as a name, it's the most common way to get information about a type's size at compile time. You can use it in preprocessor #if directives to perform conditional compilation based on a type's size.
Example:
#include <stdio.h>
int main() {
// This is NOT getting the type name, but it's a common way
// to work with types in a generic way.
int my_int = 10;
double my_double = 20.5;
printf("Size of int: %zu bytes\n", sizeof(my_int)); // Output: 4 bytes
printf("Size of double: %zu bytes\n", sizeof(my_double)); // Output: 8 bytes
// Conditional compilation based on type size
#if sizeof(int) == 4
printf("This compiler uses 4-byte integers.\n");
#endif
return 0;
}
Limitation: This only tells you the size, not the type itself.

Compiler-Specific typeof (GCC and Clang)
GCC (and its derivative Clang) support a powerful extension called typeof. This is the closest you'll get to a true typeof operator in standard C. It's very useful for writing generic macros.
Syntax:
typeof(expression): Gets the type of the result of an expression.typeof(type): Gets the type directly.
Example (GCC/Clang only):
#include <stdio.h>
// A generic macro to swap two values of any type
#define SWAP(a, b) do { \
typeof(a) temp = a; \
a = b; \
b = temp; \
} while(0)
int main() {
int x = 5, y = 10;
printf("Before swap: x = %d, y = %d\n", x, y);
SWAP(x, y);
printf("After swap: x = %d, y = %d\n", x, y);
double d1 = 3.14, d2 = 6.28;
printf("\nBefore swap: d1 = %f, d2 = %f\n", d1, d2);
SWAP(d1, d2);
printf("After swap: d1 = %f, d2 = %f\n", d1, d2);
return 0;
}
Output:

Before swap: x = 5, y = 10
After swap: x = 10, y = 5
Before swap: d1 = 3.140000, d2 = 6.280000
After swap: d1 = 6.280000, d2 = 3.140000
Limitation: This is not standard C. Code using typeof will not compile on compilers that don't support it (like MSVC by default).
The Modern Standard C Solution: _Generic (C11)
Since C11, the standard includes _Generic, which is a powerful feature for generic programming. It allows you to select an expression based on the type of an expression. It's the standard way to create type-safe generic macros and functions.
How it works: _Generic takes a controlling expression and a series of type-name: association pairs. It evaluates the association that matches the type of the controlling expression.
Example: Let's create a macro that safely prints any type.
#include <stdio.h>
// A generic "print" macro
#define PRINT(x) _Generic((x), \
int: print_int, \
double: print_double, \
const char*: print_string \
)(x)
// Helper functions for each type
void print_int(int i) {
printf("Integer: %d\n", i);
}
void print_double(double d) {
printf("Double: %f\n", d);
}
void print_string(const char* s) {
printf("String: %s\n", s);
}
int main() {
int a = 100;
double b = 3.14159;
const char* c = "Hello, C11!";
PRINT(a);
PRINT(b);
PRINT(c);
return 0;
}
Output:
Integer: 100
Double: 3.141590
String: Hello, C11!
Limitation: _Generic doesn't give you the type as a string or a variable of type type. It's a compile-time dispatch mechanism. You have to list all the types you want to handle explicitly.
Advanced: Getting the Type as a String (Non-Standard)
If your goal is to get the name of the type as a string (e.g., "int", "double"), this is not possible in standard C. The C preprocessor and compiler do not have a way to generate a string literal from a type name.
However, some compilers offer non-standard extensions for this. For example, GCC has __typeof__ and a way to stringify type names using and __VA_ARGS__ tricks, but it's complex and not portable.
Example (GCC-specific, advanced macro):
// This is a GCC-specific trick and not recommended for portable code
#define TYPESTR(x) _Generic((x), \
int: "int", \
double: "double", \
default: "unknown type" \
)
int main() {
int my_var = 42;
printf("The type of my_var is: %s\n", TYPESTR(my_var)); // Output: The type of my_var is: int
return 0;
}
This uses _Generic to select a string literal, effectively creating a "type-to-string" mapping. It's still limited to the types you explicitly list.
Summary Table
| Method | Standard C? | Use Case | Portability |
|---|---|---|---|
sizeof(type) |
Yes | Getting the size of a type; conditional compilation. | Excellent (All C compilers) |
typeof (GCC/Clang) |
No | Creating generic macros that work with any type. | Poor (GCC, Clang, ICC only) |
_Generic (C11) |
Yes | Writing type-safe generic functions and macros. | Good (Modern C11 compilers) |
| Stringify Type Name | No | Getting a type's name as a string (e.g., "int"). | Very Poor (Compiler-specific hacks) |
Conclusion
- For portable, standard C code, use
_Generic(C11 and later) for generic programming andsizeoffor size-based conditional logic. - If you are targeting GCC or Clang and need a simple
typeoffor macros,typeofis an excellent and powerful choice. - Getting a type's name as a string is not possible in standard C and should be avoided for portable code.
