Question

I'm currently refactoring/tidying up some old C code used in a C++ project, and regularly see functions such as:

int f(void)

which I would tend to write as:

int f()

Is there any reason not to replace (void) with () throughout the codebase in order to improve consistency, or is there a subtle difference between the two that I am unaware of? More specifically, if a virtual member function in C++ is described as:

virtual int f(void)

and a derived class includes a member function:

int f()

is this a valid override? Additionally, am I likely to encounter any linker problems based on almost identical signatures?

Was it helpful?

Solution

In C, the declaration int f(void) means a function returning int that takes no parameters. The declaration int f() means a function returning int that takes any number of parameters. Thus, if you have a function that takes no parameters in C, the former is the correct prototype.

In C++, I believe int f(void) is deprecated, and int f() is preferred, as it specifically means a function that takes no parameters.

OTHER TIPS

To add to Chris's answer, using int f() is bad practice in C, in my experience, since you lose the compiler's ability to compare the function's declaration to its definition, to ensure that it will be called correctly.

For example, the following code is standards-compliant C:

#include <stdio.h>
void foo();
void bar(void) {
    foo();
}
void foo(int a) {
    printf("%d\n", a);
}

But it results in undefined behavior, since a was not passed to foo.

In C++, there are two versions of foo: one that takes no arguments and one that takes an int. So bar winds up calling the undefined version, which would result in a linker error (assuming there are no other definitions of foo anywhere).

The answers above are quite correct, but I'm linking to David Tribble's excellent page as it gives a great explanation on this and many other issues.

The highlights:

C distinguishes between a function declared with an empty parameter list and a function declared with a parameter list consisting of only void. The former is an unprototyped function taking an unspecified number of arguments, while the latter is a prototyped function taking no arguments.

C++, on the other hand, makes no distinction between the two declarations and considers them both to mean a function taking no arguments.

For code that is intended to be compiled as either C or C++, the best solution to this problem is to always declare functions taking no parameters with an explicit void prototype.

Empty function prototypes are a deprecated feature in C99 (as they were in C89).

Edit: After looking at the standard, it's perhaps worth noting that the func(void) syntax is not deprecated in C++, but it's commonly considered more of a C-style idiom. I think most C++ programmers I've run across prefer the empty parameter list.

Edit 2: Adding a quote from the C++ standard, section 8.3.5, paragraph 2:

"If the parameter-declaration-clause is empty, the function takes no arguments. The parameter list (void) is equivalent to the empty parameter list. Except for this special case, void shall not be a parameter type (though types derived from void, such as void*, can)."

There's no mention that either form is deprecated. Thanks again to Mr. Tribble's excellent website for pointing me to the correct section of the standard.

tl;dr: use void.

Given the backward compatibility in C++, and the bit of ambiguity identified below, I assert that we go all the way back to KnR and ANSI C for a conclusive answer:

int getline(void);
int copy(void)

Since the specialized versions of getline and copy have no arguments, logic would suggest that their prototypes at the beginning of the file should be getline() and copy(). But for compatibility with older C programs the standard takes an empty list as an old-style declaration, and turns off all argument list checking; the word void must be used for an explicitly empty list. [Kernighan & Richie, the C programming language, 1988, Pgs 32-33]

and..

The special meaning of the empty argument list is intended to permit older C programs to compile with new compilers. But it's a bad idea to use it with new programs. If the function takes arguments, declare them; if it takes no arguments, use void [ibid, Pg. 73]

EDIT: Broke the rest into a separate discussion here: Does specifying the use of void in the declaration of a function that takes no arguments address The Most Vexing Parse?

C11 N1570 standard draft

void f() is deprecated, void f(void) recommended:

6.11.6 Function declarators:

1 The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.

Introduction:

2 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 (for implementation features) or new programs (for language [6.11] or library features [7.31]) is discouraged.

Detailed discussion: https://stackoverflow.com/a/36292431/895245

C++11 N3337 standard draft

Neither void f(void) nor void f() are deprecated.

void f(void) exists for compatibility with C. Annex C "Compatibility" C.1.7 Clause 8: declarators:

8.3.5 Change: In C ++ , a function declared with an empty parameter list takes no arguments. In C, an empty parameter list means that the number and type of the function arguments are unknown.

Since void f() is deprecated in C and void f(void) recommended, void f(void) will exist for as long as C++ wants to maintain compatibility.

void f(void) and void f() are the same in C++. So the longer void f(void) only makes sense if you care about writing code that compiles under both C and C++, which is likely not worth it.

Detailed discussion: https://stackoverflow.com/a/36835303/895245

In C++, int f(void) is indeed a deprecated declaration which is 100% equivalent to int f(). It is the same signature. The void in this context is as significant as e.g. whitespace. That also means that they are subject to the One Definition Rule (they don't overload) and Derived::f(void) overrides Base::f().

Don't mess with stuff like f(const void), though. There's not a lot of consensus what that kind of weirdness means.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top