Deep C Dives: Into the Void
Written by Mike James
Tuesday, 11 June 2024
Article Index
Deep C Dives: Into the Void
The Void Type

You can’t help having encountered the mysterious void data type. It sounds like something from SciFi and, along with the semi-colon, accounts for a C program’s intimidating look to the beginner. As time ticks on, however, we get used to the void and eventually hardly notice it. But why “void” and what exactly does it mean? Find out in this extract from my latest book Deep C Dives

Deep C Dives Adventures in C

Buy from Amazon.

Contents

Preface
Prolog C
Dive

1. All You Need Are Bits
2. These aren’t the types you’re looking for
3. Type Casting
4. Expressions
5. Bits and More Bits
6. The Brilliant But Evil for
7. Into the Void
8. Blocks, Stacks and Locals
9. Static Storage
10. Pointers
11. The Array and Pointer Arithmetic
12. Heap, The Third Memory Allocation
13. First Class Functions
Extract:
First Class Functions ***NEW!
14. Structs and Objects
15. The Union
16. Undefined Behavior
17. Exceptions and the Long Jump

<ASIN:B0D6LZZQ8R>

Into the Void

I'll get me to a place more void.

William Shakespeare

Why Void?

As far as I can determine the use of “void” as a type was introduced in Algol 68 and its language designers also seem to have liked related terms like “voiding”. The word is defined by wiktionary as:

1. Containing nothing; empty; not occupied or filled.

2. Having no incumbent; unoccupied; said of offices etc.

3. Being without; destitute; devoid.

4. Not producing any effect; ineffectual; vain.

5. Of no legal force or effect, incapable of confirmation or ratification.

6. Containing no immaterial quality; destitute of mind or soul.

7. Of a function or method that does not return a value.

My guess is that it is the first definition that comes into everyone’s mind when they read “void” in a program, but I actually think it is the fifth that explains why we use it.

The original idea was that a C function should define, not only the types of its parameters, but the type of its return value. So you might write

`int sum(int a, int b){…`

to mean that sum returns an int. This allows the compiler to check that the function really does return an int at compile time.

Essentially, if the function has a return c; instruction and c is confirmed to be an int then everything is fine.

This idea raises the issue of what to do when a function is a procedure?

Functions always return a result. Functions that don't return a result are more properly called “procedures” or “subroutines”. Other languages sometimes provide different syntax for a function, which returns a result, and procedures, which don’t. In the case of C, and many modern languages, we simply have functions and we need a way to show that no result is returned. If you think about:

`int sum(int a, int b){…`

as being a contract that sum will return something, which in this case is an int then you might think that a function that didn’t return anything broke its contract to be a function, i.e. the contract was null and void.

Well that’s my theory and it helps to see why void might be appropriate.

Void In C

We now appreciate the idea of

`void sum(int a, int b){…`

declaring a function that doesn’t return a result – indeed that must not return a result. If sum did return a result then you would see a compile error something like:

`'void' function returning a value`

Notice that in C you can choose to ignore any return value. What happens is that the value that is returned on the stack is simply thrown away. For example in:

```int sum(int a, int b){
return a+b;
}
sum(1,2);```

you are throwing away the result and you won’t even see a warning in most cases as this is perfectly valid C. Contrast this with a function that returns void which has to be called in this way.

You might be familiar with void being used to turn functions into procedures, but what about functions that don’t accept parameters? It is common to see:

```int sum(){
return 1+2;
}
printf(“%d\n”,sum());```

but this is mostly wrong. It doesn’t declare a function with no parameters. It declares a function with a fixed, but unknown, number of parameters.

With that definition you can still write:

`printf("%d\n",sum(1,2));`

and generate no compiler or runtime errors. Of course, with this declaration the function cannot access the parameters, but you can separate the declaration and implementation of the function:

```int sum();
int main(int argc, char **argv)
{
printf("%d\n",sum(1,2));
}
int sum(int a, int b){
return a+b;
}```

In this case the function is defined after the main program. So the first declaration is needed and it declares a function with no parameters – only, of course, it doesn’t. It declares a function with any number of parameters which is why the program works – you might see a warning message from a helpful IDE or compiler. This is so confusing that C99 outlawed the use of function() at all and you have to use function(void).

If you replace int sum(); by int sum(void); in the previous program you will see an error message as the definition of sum has parameters and its declaration states that it doesn’t have any.

To summarize:

• Use void function(...) to state that a function definitely doesn’t return a result.

• Use type function(void) to state that a function definitely doesn’t take any parameters.

See Dive 13 for more.

Void Expressions

A little known use of void is to create a void expression. Expressions are like functions in that they return a result. Usually, if you want to ignore the value of an expression then you can simply do that, for example:

`2+3;`

Such expressions are generally called “statement expressions”. If you want to make it clear that an expression is throwing away its result you can cast the result to void. That is, the previous statement expression is equivalent to:

`(void)(2+3);`

Last Updated ( Monday, 17 June 2024 )