foo(void) vs foo(void *)
Asked Answered
T

3

9

Functionally and syntactically speaking, is there a difference between a function whose prototype is int foo(void) and int foo(void *)?

I know the difference between, for example, int bar(int) and int bar(int *) - one of them is looking for an int, and the other is looking for an int pointer. Does void behave the same way?

Trigraph answered 12/11, 2019 at 16:17 Comment(3)
An answer to a related question: https://mcmap.net/q/128955/-what-does-void-mean-in-c-c-and-c.Timeous
Related (although not dupes as I can see): Is there a difference between foo(void) and foo() in C++ or C? - What is the difference between function() and function(void)? - What does an empty parameter list mean?Plague
What may be more interesting is the difference between foo(void) and foo().Deictic
T
11

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.

Trigraph answered 12/11, 2019 at 16:17 Comment(2)
void * ... must be cast to another type first, but may be done so without an explicit cast. Not true in C++. In C++ the conversion form void* must be explicit. P.S. calling a cast explicit is redundant since cast is by definition an explicit conversion.Sparerib
Updated to reflect C/C++ differences, thank you for letting me know!Trigraph
R
5

foo(void) - function with no parameters

foo(void *) - function with one void * parameter

What is void *? It is just the pointer to the data with no specified type. It Can be casted to any other pointer type

unsigned add(void *arr)
{
   unsigned *uarr = arr;
   return uarr[0] + uarr[1];
}
Respectively answered 12/11, 2019 at 16:20 Comment(1)
Essential answer, so it is the best one. I would just hilight how this is an exception in the (type) vs. (type *) couples universe because void is not actually a type.Recalescence
S
2

Functionally and syntactically speaking, is there a difference between a function whose prototype is int foo(void) and int foo(void *)?

There is a difference:

int foo(void) declares a function that accepts no arguments.

int foo(void *) declares a function that accepts single argument of type void*.

In C++, int foo(void) is equvalent to int foo().

Sparerib answered 12/11, 2019 at 16:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.