cfunctionfunction-prototypes

Why do we need prototype in function?


I'm studying C and my book is explaining how to "prototype a function" so we can use it before we define it.

The point is that I can't imagine a situation in which is needed to use a function before have defined it, why can't we just define it at the beginning?

Can you please provide an example in which is strictly necessary to prototype a function (if it exists)?


Solution

  • One use-case is when you want to take a function pointer to a function defined in another source file. (Or hand-written in asm). Taking a function-pointer always requires the function to be declared ahead of time, either by a definition or a prototype.

    C89 (and earlier) allows implicit declaration of functions (use them even if there's no definition or prototype earlier in the compilation unit (this .c + anything you #include).

    So you can compile this in a file by itself, in C89 (or with a warning from most compilers in C99 / C11 mode)

    int foo() {
        return bar( 123 );   /* implicit declaration of  int bar()  */
    }
    

    But you can't use &bar as a function pointer

    /* int bar(int);      necessary if you haven't defined  int bar(int x) { ... } */
    void *take_fptr() {
         return &bar;    // error: 'bar' undeclared   from GCC
    }
    

    You can also construct cases where a declaration is needed to get args passed correctly, e.g. if you want your function to take a float arg, you need it to be declared, either by a definition or prototype. The "Default Argument Promotions" in the ISO C standard will promote float to double when passing an arg to an unprototyped function, or to the ... part of a variadic function like printf.

    (That's why %f prints a double, not a float, and why %lf is also a double if it's supported at all. Also why functions like putchar(int) take their char arg as an int: default promotions of narrow integer types up to int. Some parts of the C standard library date back to very early C, before the language supported prototypes!)

    Or for example, if your function is expecting a long long, but the caller writes bar( 123 ), the caller will only infer int, which may be passed differently from a long long. But you can fix that by writing bar( 123LL ), or bar( (long long)123 )

    Or if the return type isn't int (or void), then you also need the compiler to know about the function via a declaration. Implicitly-declared functions are assumed to return int. Depending on the calling convention and architecture, you might get away with that for a short return type, or on some machines even for a char*, e.g. on 32-bit machines where intptr_t is int. (Early C relied on that.)

    But in general, e.g. on machines with 64-bit pointers, implicit-int return isn't going to work. Nor will it work for a double return value, or a struct.