Why is void classified differently from other basic types?

92 views Asked by At

On cppreference.com they classify types as:

  1. Void types
  2. Basic types
  3. Enumerated types
  4. Derived types

I cannot find the reason why they have classified void as a fundamental type. It implies that there is a difference between basic types like int, char, etc., and the void type. On the basis of whether they are storing values or not, they clearly differ: conceptually, void type denotes objects that do not store any values, but basic-typed objects do store values.

I feel that every classification should have a single and well-defined basis. But here, I feel that there is no single basis.

In my opinion, instead they could have classified them on the basis of whether is it derived or not:

  1. Basic types (includes void as well)
  2. Derived types (types that are derived using the basic types. includes enum types as well)

Here, I classified void as basic type because it is one of the standard types defined in standard and doesn't depend on any other types. I classified enum types as derived types because I viewed that the enum types represent values of int type, therefore concluding that enum types are derived (implicitly) from int type.

What could be there basis of classification? Does my classification makes sense?

2

There are 2 answers

7
gulpr On

It implies that there is a difference between basic types like int, char, etc., and the void type.

How void differs from other types:

  • void is incomplete by definition.
  • You can't declare a variable of type void
  • You cant have a void struct or union member
  • You can't have an array of void elements
  • You can't do pointer arithmetic on void pointers
  • You can't dereference void pointers

Did I miss something?

Imagine an empty space. You can have this place coordinates (pointer). But do you think that it can be classified the same as planets or stars?

0
Eric Postpischil On

First, cppreference.com’s classifications are its own choice. They do come from the standard in some sense, because C 2018 6.2.5 14 defines the basic types:

The type char, the signed and unsigned integer types, and the floating types are collectively called the basic types. The basic types are complete object types. Even if the implementation defines two or more basic types to have the same representation, they are nevertheless different types.

C 2018 6.2.5 16 defines the enumerated types:

An enumeration comprises a set of named integer constant values. Each distinct enumeration constitutes a different enumerated type.

C 2018 6.2.5 20 defines the derived types:

Any number of derived types can be constructed from the object and function types, as follows:…

and that leaves void out in the cold, on its own and not explicitly stated to be part of any class of types, in C 2018 6.2.5 19:

The void type comprises an empty set of values; it is an incomplete object type that cannot be completed.

But the standard does not say these four categories are the way to classify types or that they are particularly notable. For example, cppreference.com could have said there are three categories, void, arithmetic, and derived, because arithmetic types include the basic types and enumerated types. Why did cppreference.com choose to split enumerated types off separately instead of adopting arithmetic types as the category? That is their own choice. It is an opinion, not a rule of the C standard.

That said, we can ask what makes void different from other types. Fundamentally, void is not intended to be used directly. Its primary purpose is to enable void * to serve as a generic pointer: A void * is a pointer to something, but we do not know what from the type alone. To use a void *, we do not dereference it to get a void. Instead, we convert it to a pointer to another type, such as a char * or a double * and use that.

The way the authors of the C standard made this work is to specify that the void type is incomplete. Incompleteness in C’s type system means we do not know something about a type. For example:

  • int a[] is an array, but we do not know how many elements it has.
  • struct foo is a structure, but we do not know what is in it.

With ordinary types, we can complete them. After int a[]; declares an incomplete a, we can complete it with int a[3];. After struct foo declares an incomplete structure, we can complete it with struct foo { int i; }. However, void is specified to be a type that cannot be completed. After extern void x;, you cannot write int x; to say “That unknown thing is actually an int.” This makes it special because no other type has this rule.

So it is reasonable to put void in its own category. Nonetheless, it remains an opinion what categories to use, not a rule of the C standard.