typeof / typeof_unqual
/ TIPE-of /
Sometimes you want to declare a new variable with EXACTLY the same type as some existing expression, without writing the type name out — handy in macros where you do not know the caller's type. The typeof operator, long a GNU extension and standardized in C23, gives you the type of an expression (or of a type), which you can then use anywhere a type name is allowed.
typeof(expr) yields the type of expr, and typeof(T) yields T itself. So typeof(x) y; declares y with the same type as x, and typeof(int *) p; declares p as an int *. As with sizeof, typeof does NOT evaluate its operand when the operand is just an expression (it only inspects the type), so there are no side effects. C23 also adds typeof_unqual, which gives the same type but with top-level qualifiers like const and volatile STRIPPED off — useful when you want a fresh, writable copy's type rather than a read-only one. For example, if x is const int, typeof(x) is const int but typeof_unqual(x) is plain int.
It matters most inside macros that must work for any argument type: a safe MAX macro can save its arguments in temporaries of their own type to evaluate each once, written with typeof. The caveat: typeof captures the static type precisely, including qualifiers and array-ness, which is powerful but means you sometimes specifically want typeof_unqual to drop a const you do not want to carry along.
#define MAX(a, b) ({ typeof(a) _x = (a); typeof(b) _y = (b); \ _x > _y ? _x : _y; }) const int c = 5; typeof(c) d = c; // d is const int typeof_unqual(c) e = c; // e is plain int (const stripped)
typeof copies an expression's exact type into a new declaration; typeof_unqual does the same but drops top-level const/volatile.
typeof captures qualifiers too, so typeof(const int) keeps the const; reach for typeof_unqual when you want an unqualified, writable copy of the type.