68

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?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
SmacL
  • 22,555
  • 12
  • 95
  • 149
  • 11
    Be careful not to lump C and C++ too closely together like this. There are differences that need to be taken into consideration... – Brian Knoblauch Jan 06 '09 at 13:33
  • I'm realising this more as I read the posts below. The refactor is to C++ in this case and dropping some C compatibility or style is not an issue. – SmacL Jan 06 '09 at 13:59
  • 1
    Dup: http://stackoverflow.com/questions/7412274/why-add-void-to-method-parameter-list – Will Bickford Aug 09 '12 at 16:50
  • 4
    @Will, dup question asked 2 years later ;) – SmacL Aug 09 '12 at 18:25
  • 3
    @Shane: I can see through time! The other answer has better detail. :) – Will Bickford Aug 10 '12 at 11:57
  • If the C++ standards had _required_ the void in the signature, then I believe they could have avoided the Most Vexing Parse. – Adrian McCarthy Sep 13 '12 at 17:36
  • 1
    @Ciro, similar question but not the same, in that I'm asking whether or not one version is deprecated and a candidate for refactoring, and if so is it liable to lead to possible signature clash problems when working with other code, including statically linked libraries. – SmacL Jul 03 '15 at 08:10

6 Answers6

101

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.

Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
Chris Young
  • 15,627
  • 7
  • 36
  • 42
  • 24
    I did not know that void f() meant any number of parameters in C, thanks for pointing that out. – Dominik Grabiec Jan 06 '09 at 13:58
  • 14
    i wouldn't word it with "takes any number of parameters", because it means "takes an unknown number of parameters of unknown types". giving it the wrong number results in undefined behavior. "..." means that it takes any numbers of additional parameters – Johannes Schaub - litb Jan 06 '09 at 16:05
  • 1
    As far as I know, that syntax is not deprecated (Stroustrup himself said "every program in the K&R book is also a valid C++ program" but (as others point out), considered a C-ism. I prefer to use it to explicitly say a function takes no arguments. It also helps if you need to share code with C. – Joe Pineda Feb 28 '09 at 05:22
  • 4
    You're right, Joe, it's not deprecated syntax in C++. I checked the standard myself earlier. But funny enough, the empty parameter list has been deprecated syntax in C since 1989! – Dan Olson Feb 28 '09 at 06:50
  • +1 When coding C code for safety applications (automotive, aerospace, etc.) strict coding guidelines (e.g. MISRA for automotive) must be followed and one is that you need to write `f(void)` and not `f()`. This is indeed because of the reasons stated by this answer. – Martin Scharrer Apr 13 '17 at 11:36
21

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).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Zach Hirsch
  • 24,631
  • 8
  • 32
  • 29
  • Good point, thanks. But I think you should add it's bad practice in C, but not C++. – Chris Young Jan 06 '09 at 12:45
  • 2
    I am not convinced you need the "in my experience" qualifier; it is pretty much unreservedly bad practice. The only time it would be acceptable is if the C compiler is a pre-C89 compiler that does not accept function prototypes; they are rare indeed these days. – Jonathan Leffler Jan 06 '09 at 13:41
18

The previous answers 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).

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.

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dan Olson
  • 22,849
  • 4
  • 42
  • 56
2

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

Community
  • 1
  • 1
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
2

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 K&R 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]

I 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?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kmiklas
  • 13,085
  • 22
  • 67
  • 103
-1

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.

hochl
  • 12,524
  • 10
  • 53
  • 87
MSalters
  • 173,980
  • 10
  • 155
  • 350
  • 1
    The answer above this says that f(void) is NOT deprecated. Will someone provide a link to or quote from the standard that talks about the deprecation (or lack thereof) of f(void)? – Chris Lutz Feb 28 '09 at 05:05
  • I've edited my answer to include the quote and citation. – Dan Olson Mar 01 '09 at 12:45