195

I have a library I created,

File mylib.c:

#include <mylib.h>

int
testlib() {
    printf("Hello, World!\n");
    return (0);
}

File mylib.h:

#include <stdio.h>
extern int testlib();

In my program, I've attempted to call this library function:

File myprogram.c:

#include <mylib.h>

int
main (int argc, char *argv[]) {
    testlib();
    return (0);
}

When I attempt to compile this program I get the following error:

In file included from myprogram.c:1
mylib.h:2 warning: function declaration isn't a prototype

I'm using: gcc (GCC) 3.4.5 20051201 (Red Hat 3.4.5-2)

What is the proper way to declare a function prototype?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alan H
  • 3,021
  • 4
  • 25
  • 24
  • 1
    Remove extern from the declaration in mylib.h Especially if you are writing a pure C program, the extern declaration is unnecessary there. – Ryan Ahearn Sep 03 '08 at 17:16

3 Answers3

404

In C int foo() and int foo(void) are different functions. int foo() accepts an arbitrary number of arguments, while int foo(void) accepts 0 arguments. In C++ they mean the same thing. I suggest that you use void consistently when you mean no arguments.

If you have a variable a, extern int a; is a way to tell the compiler that a is a symbol that might be present in a different translation unit (C compiler speak for source file), don't resolve it until link time. On the other hand, symbols which are function names are anyway resolved at link time. The meaning of a storage class specifier on a function (extern, static) only affects its visibility and extern is the default, so extern is actually unnecessary.

I suggest removing the extern, it is extraneous and is usually omitted.

heinrich5991
  • 2,694
  • 1
  • 19
  • 26
Pramod
  • 9,256
  • 4
  • 26
  • 27
  • 13
    Use `(void)` *in C* to indicate that a function takes no arguments. In C++, unless you specifically need your code to compile both as C and as C++, just use `()`. – Keith Thompson Dec 30 '13 at 16:50
  • @Pramod Thanks so much for this explanation. Gosh, it cleared things up. – William Martens Apr 19 '21 at 05:35
  • Note that this is going to change with C23 ( https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2432.pdf ): "we propose to enforce the empty list as to be as if a list of void had been given" – Étienne May 12 '23 at 09:58
  • See also the latest draft of C23 ( https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf ): "For a function declarator without a parameter type list: the effect is as if it were declared with a parameter type list consisting of the keyword void. ". – Étienne May 12 '23 at 10:02
66

Quick answer: change int testlib() to int testlib(void) to specify that the function takes no arguments.

A prototype is by definition a function declaration that specifies the type(s) of the function's argument(s).

A non-prototype function declaration like

int foo();

is an old-style declaration that does not specify the number or types of arguments. (Prior to the 1989 ANSI C standard, this was the only kind of function declaration available in the language.) You can call such a function with any arbitrary number of arguments, and the compiler isn't required to complain -- but if the call is inconsistent with the definition, your program has undefined behavior.

For a function that takes one or more arguments, you can specify the type of each argument in the declaration:

int bar(int x, double y);

Functions with no arguments are a special case. Logically, empty parentheses would have been a good way to specify that a function takes no arguments, but that syntax was already in use for old-style function declarations, so the ANSI C committee invented a new syntax using the void keyword:

int foo(void); /* foo takes no arguments */

A function definition (which includes code for what the function actually does) also provides a declaration. In your case, you have something similar to:

int testlib()
{
    /* code that implements testlib */
}

This provides a non-prototype declaration for testlib. As a definition, this tells the compiler that testlib has no parameters, but as a declaration, it only tells the compiler that testlib takes some unspecified but fixed number and type(s) of arguments.

If you change () to (void) the declaration becomes a prototype.

The advantage of a prototype is that if you accidentally call testlib with one or more arguments, the compiler will diagnose the error.

(C++ has slightly different rules. C++ doesn't have old-style function declarations, and empty parentheses specifically mean that a function takes no arguments. C++ supports the (void) syntax for consistency with C. But unless you specifically need your code to compile both as C and as C++, you should probably use the () in C++ and the (void) syntax in C.)

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
23

Try:

extern int testlib(void);
Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825