Search code examples
cfunctionprototype

Can't understand how to create a prototype of a procedure without parameters


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?


Solution

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