From this answer on Software Engineering, void
is treated specially depending on how it's used. In C
and C++
, void
is used to indicate an absence of a data type, whereas void *
is used to indicate a pointer which points to some data/space in memory that does not have a type. void *
cannot be dereferenced on its own, and must be cast to another type first. This cast need not be explicit in C
, but must be explicit in C++
. (This is why we don't cast the return value of malloc, which is void *
.)
When used with a function as a parameter, void
means a total absence of any parameters, and is the only parameter allowed. Attempting to use void like a variable type or include other arguments results in a compiler error:
int foo(void, int); //trying to use "void" as a parameter
int bar(void baz); //trying to use "void" as an argument's type
main.c:1:8: error: 'void' must be the first and only parameter if specified
int foo(void, int);
^
main.c:2:14: error: argument may not have 'void' type
int bar(void baz);
^
It is similarly impossible to declare a variable with type void
:
int main(void) {
void qux; //trying to create a variable with type void
}
main.c:5:8: error: variable has incomplete type 'void'
void qux;
void
as a return value for a function indicates no data will be returned. Since it is impossible to declare a variable of type void
, it is impossible to catch the return value of a void
function, even with a void pointer.
void foo(int i) { return; }
int main(void) {
void *j;
j = foo(0);
return 0;
}
main.c:5:5: error: assigning to 'void *' from
incompatible type 'void'
j = foo(0);
^ ~~~~~~
The typeless void *
is a different case. A void pointer indicates a pointer to a location in memory, but does not indicate the type of data at that pointer. (This is the used to achieve polymorphism in C, such as with the qsort() function.) These pointers can be tricky to use, however, as it is very easy to accidentally cast them to the wrong type. The code below won't throw any compiler errors in C
, but results in undefined behavior:
#include <stdio.h>
int main(void) {
double foo = 47.2; //create a double
void *bar = &foo; //create a void pointer to that double
char *baz = bar; //create a char pointer from the void pointer, which
//is supposed to hold a double
fprintf(stdout, "%s\n", baz);
}
The following code, however, is perfectly legal; casting to and from a void pointer never changes the value it holds.
#include <stdio.h>
int main(void) {
double foo = 47.2;
void *bar = &foo;
double *baz = bar;
fprintf(stdout, "%f\n", *baz);
}
47.200000
As a function parameter, void *
indicates that the type of the data at the pointer you are passing in is not known, and it is up to you, the programmer, to properly handle whatever is at that memory location. As a return value, void *
indicates that the type of the data being returned is not known or is typeless, and must be handled by the program.
int quux(void *); //a function that receives a pointer to data whose type is not known, and returns an int.
void *quuz(int); //a function that receives an int, and returns a pointer to data whose type is not known.
tl;dr void
in a function prototype means "no data" and indicates no return value or no parameters, void *
in a function prototype means "the data at the pointer this function is given does not have a known type" and indicates a parameter or return value whose pointer must be cast to a different type before the data at the pointer can be used.
foo(void)
andfoo()
. – Deictic