Is There a Difference Between Foo(Void) and Foo() in C++ or C

Is there a difference between foo(void) and foo() in C++ or C?

In C:

  • void foo() means "a function foo taking an unspecified number of arguments of unspecified type"
  • void foo(void) means "a function foo taking no arguments"

In C++:

  • void foo() means "a function foo taking no arguments"
  • void foo(void) means "a function foo taking no arguments"

By writing foo(void), therefore, we achieve the same interpretation across both languages and make our headers multilingual (though we usually need to do some more things to the headers to make them truly cross-language; namely, wrap them in an extern "C" if we're compiling C++).

foo(void) vs foo(void *)

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.

Is it better to use C void arguments void foo(void) or not void foo()?

void foo(void);

That is the correct way to say "no parameters" in C, and it also works in C++.

But:

void foo();

Means different things in C and C++! In C it means "could take any number of parameters of unknown types", and in C++ it means the same as foo(void).

Variable argument list functions are inherently un-typesafe and should be avoided where possible.

Definition of `int foo() {}` vs `int foo(void) {}` following declaration of `int foo(void);`

The code you have posted is correct. int foo2(void); declares foo2 as taking no arguments, and forms a prototype.

The function definition must be compatible with this; and a definition with empty parentheses is compatible with this prototype. This is specified in C11 6.7.6.3/15, which is a mouthful:

For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions. If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list, both shall agree in the number of parameters, and the type of each prototype parameter shall be compatible with the type that results from the application of the default argument
promotions to the type of the corresponding identifier. (In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.)

The reason there's so much text on this point is that C originally only had K&R style functions, and then prototypes were added . So there has to be text to cover all possible combinations of K&R style mixed with prototype style . The section beginning with my bolded part refers to using a K&R-style function definition when the function has previously been declared with a prototype.


Also relevant: use of empty parentheses is obsolescent in C11 (6.11.6).

Certain features are obsolescent, which means that they may be considered for
withdrawal in future revisions of this International Standard. They are retained because of their widespread use, but their use in new implementations or new programs is discouraged.

Implications of typedef void FOO vs. #define FOO void in function signatures

A simple test program in C++ demonstrates the difference:

typedef void VOID;

void f(VOID) {}

int main()
{
f();
}

On compilation (as C++), it gives these error:

prog.cpp:5:8: error: '<anonymous>' has incomplete type
void f(VOID) {}
^
prog.cpp:5:12: error: invalid use of 'VOID {aka void}'
void f(VOID) {}
^
prog.cpp: In function 'int main()':
prog.cpp:9:7: error: too few arguments to function 'void f(<type error>)'
f();
^
prog.cpp:5:6: note: declared here
void f(VOID) {}
^

which explains what the comment means in your code. In particular, it seems the typedef VOID attempts to be a type different from void, when it is used as parameter type.

Difference Between c.foo() and c.parent::foo()

It would appear that c.() and c.parent::() are the same.

They are same only if child does not have a function of the same name.

Does this syntax exist only for multiple inheritance?

No. There are times when you need to call the implementation of a function in a parent class.

Or is there some nuance where even without multiple inheritance the parent:: scope specifier would be different?

Yes.

Example:

#include <iostream>

class parent {
public:
virtual void print() const
{
std::cout << "In parent::print()\n";
}

};

class child : public parent {
public:
virtual void print() const
{
std::cout << "In child::print()\n";
}
};

void print(parent& p)
{
p.print(); // Goes to child::print() when p references a child
p.parent::print(); // Goes to parent::print() regardless
}

int main()
{
child c;
print(c);
}

Output

In child::print()
In parent::print()

Also, there are times when you need to invoke the parent's implementation of a virtual member function from the child's implementation.

Example:

#include <iostream>

class parent {
public:
virtual void save(std::ostream& out) const
{
// Save the data corresponding to this class.
}

};

class child : public parent {
public:
virtual void save(std::ostream& out) const
{
// Save the data corresponding to parent first.
parent::save(out);

// Save the data corresponding to this class.
}
};

void save(parent& p, std::ostream& out)
{
p.save(std::cout); // Calls child::save() when p references a child,
// which in turn calls parent::save()
}

int main()
{
child c;
save(c, std::cout);
}


Related Topics



Leave a reply



Submit