typeof in C23
Tags: c
Published: 2024-01-23 15:03:29

---
title: typeof in C23
published: true
description: A description of the typeof and typeof_unqual keywords in C23.
tags: #c
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2024-01-22 19:04 +0000
---

## Introduction

Among other things, [C23](https://en.wikipedia.org/wiki/C23_(C_standard_revision)) added the [`typeof`](https://en.cppreference.com/w/c/language/typeof) and `typeof_unqual` keywords that return the _type_ of an expression:

```c
int x;        // int (obviously)
typeof(x) y;  // also int
```

> Note: for this article, I’ll simply use `typeof` to mean _either_ `typeof` _or_ `typeof_unqual` rather than always repeating “or `typeof_unqual`” unless otherwise stated.

The expression is _not_ evaluated.  Like [`sizeof`](https://en.cppreference.com/w/c/language/sizeof), `typeof` is a compile-time operator.  `typeof` standardizes the long-existing `gcc` [extension](https://gcc.gnu.org/onlinedocs/gcc/Typeof.html).

> `typeof` is sort-of like [`decltype`](https://en.cppreference.com/w/cpp/language/decltype) in C++. Why isn’t `typeof` called `decltype` in C also? (Or why isn’t `decltype` in C++ called `typeof`?) The short answer is that C++ has [references](https://dev.to/pauljlucas/c-references-3b1b) and C doesn’t — and that affects the type deduced. There’s also the [long answer](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2927.htm#existing-decltype).

But wait! Since C23 also added [`auto`](https://dev.to/pauljlucas/auto-in-c23-ij9), why is `typeof` needed?

+ Variables declared with `typeof` don’t need initializers.
+ `typeof` can clarify complicated declarations.

## Declarations without Initializers

Using `auto` always requires an initializer since the compiler deduces the type from the type of the initializer expression; using `typeof` does not:

```c
double f(void);

auto x = f();   // double
typeof(f()) y;  // double, but without initializer
```

Depending on what you’re doing, you may not want to initialize upon declaration, for example if a variable is initialized only conditionally or you need to defer initialization.

Of course you still _can_ use an initializer with `typeof` if you want to guarantee a type based on something other than the initializer:

```c
typeof(f()) y = g();  // type is what f() returns, not g()
```

## Clarifying Complicated Declarations

C in infamous for complicated declarations. Normally, complicated declarations can be simplified via `typedef`. However, `typeof` can also be used since it can also take a _type_ instead of an expression:

```c
int *p1, *q1;                   // both pointer to int
typeof(int*) p2, q2;            // same

// array 4 of pointer to function (int) returning double
double (*a1[4])(int);
typeof(double(int)) *a2[4];     // same

// function (void) returning ...
// ... pointer to function (int) returning double
double (*f1(void))(int);
typeof(double(int))* f2(void);  // same
```

While the `typeof` declarations are longer, they’re _much_ clearer.

> The ability of `typeof` to take either an expression or a type parallels the ability of `sizeof` to do the same.

You can even declare [macros](https://dev.to/pauljlucas/cc-preprocessor-macros-fh5) to create an entirely alternate declaration syntax:

```c
#define ARRAY_OF(T, N)  typeof(T[N])
#define POINTER_TO(T)   typeof(T*)

ARRAY_OF(POINTER_TO(char const), 4) pc;  // char const *pc[4]
```

## `typeof_unqual`

The difference between `typeof` and `typeof_unqual` is that the latter removes all top-level qualifiers (`_Atomic`, `const`, `restrict`, and [`volatile`](https://dev.to/pauljlucas/what-volatile-does-in-c-and-c-5147)):

```c
extern int i;
extern int const ci;
extern int *pi;
extern int const *pci;
extern int *const cpi;
extern int const *const cpci;

typeof       (i)    i2;      // int
typeof_unqual(i)    i2u;     // int
typeof       (ci)   ci2;     // int const
typeof_unqual(ci)   ci2u;    // int
typeof       (pi)   pi2;     // int *
typeof_unqual(pci)  pci2u;   // int const*
typeof       (cpi)  cpi2;    // int *const
typeof_unqual(cpi)  cpi2u;   // int *
typeof       (cpci) cpci2;   // int const *const
typeof_unqual(cpci) cpci2u;  // int const *
```

## Conclusion

`typeof` is complementary to `auto` as an addition to C for writing type-agnostic code or simplifying complicated declarations.