0

My book says that I should write a prototype of a procedure (that hasn't any parameters) like this: void test(void);

I usually write the prototype of a procedure that hasn't any parameters like this: void test(); and it works.

What is the difference between these 2 declarations?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 2
    The difference is that `void test();` doesn't establish a prototype, so you can later call `test("abc")` and `test(1)` and `test(&ptr, &str, &wotnot)` and they're all valid calls. – Jonathan Leffler Oct 17 '19 at 15:51
  • 1
    See [Are prototypes required for all functions in C89, C90 or C99?](https://stackoverflow.com/questions/434763/are-prototypes-required-for-all-functions-in-c89-c90-or-c99) Note that this is not directly a duplicate of that, though they cover some of the same territory. – Jonathan Leffler Oct 17 '19 at 16:06

2 Answers2

2

In C, an empty parameter list in a function declaration means that the function takes an unspecified number of arguments - in a definition, it means it takes no arguments:

void foo(); // declaration, number of arguments is unspecified

void foo()  // definition, number of arguments is zero
{
  ...
}

A parameter list of void in both a declaration and a definition means the function takes no arguments:

void foo( void ); // declaration, number of arguments is 0

void foo( void )  // definition, number of arguments is 0
{
  ...
}

So why is this the case?

Neither prototype declaration syntax nor the void keyword were originally part of C - there was no way to specify "this function doesn't return a value" and "this function takes this many arguments of this type". In the early Cretaceous, function definitions were written as

foo( a, b, c ) // return type of int assumed
   T a; // for arbitrary types T, Q, R
   Q b;
   R c;
 {
   // do something interesting with a, b, and c
 }

and the corresponding declaration was simply written as

foo(); // strictly not necessary, since the compiler would assume a return type of int

C originally had no mechanism to validate the number and types of arguments in a function call against a function declaration. If you called foo as

foo( x, y, z, oops );

the compiler couldn't tell you that you'd passed too many arguments, or that any of x, y, or z were the wrong type. You wouldn't know that there was a problem until runtime.

The 1989 standard introduced the void keyword along with function prototype syntax, so you could now specify the number and types of parameters in a function declaration, allowing the compiler to catch mismatches like the above:

void foo( T, Q, R ); // only need to specify types in a declaration

void foo( T a, Q b, R c )
{
  // do something interesting with a, b, c
}

and the void keyword as a parameter list meant that the function took no parameters:

void foo( void ); 

Because legacy code is forever, old-style function definitions and declarations are still supported, although implicit int typing no longer is. That's why you can still declare a function as void foo();, although best practice is to declare it as void foo( void ); if it takes no arguments. Otherwise, if you try to call foo with an argument like

foo( x );

the compiler will not be able to catch the mismatch.

John Bode
  • 119,563
  • 19
  • 122
  • 198
1

This might be a difference between C and C++.

void test(void);

Is more of a C idiom.

void test();

Is more of a C++ idiom.

Neil
  • 11,059
  • 3
  • 31
  • 56
  • 3
    This is certainly a difference between C and C++. In C++, the notation `void test();` declares that the function takes zero arguments, whereas in C, the same notation says "there is a function called `test` that returns no value and takes an indeterminate argument list — but it isn't a variadic function (with `, ...` at the end of the definition)". – Jonathan Leffler Oct 17 '19 at 15:56
  • Thank you so much! – MasterWolfx Oct 17 '19 at 16:51