Search code examples
cforward-declaration

What is the significance of forward declaration in C programming?


I am now learning C programming through Learn C the Hard Way by Zed A. Shaw. There is this code (taking from his website):

#include <stdio.h>
#include <ctype.h>

// forward declarations
int can_print_it(char ch);
void print_letters(char arg[]);

void print_arguments(int argc, char *argv[])
{
    int i = 0;

    for(i = 0; i < argc; i++) {
        print_letters(argv[i]);
    }
}

void print_letters(char arg[])
{
    int i = 0;

    for(i = 0; arg[i] != '\0'; i++) {
        char ch = arg[i];

        if(can_print_it(ch)) {
            printf("'%c' == %d ", ch, ch);
        }
    }

    printf("\n");
}

int can_print_it(char ch)
{
    return isalpha(ch) || isblank(ch);
}


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

Don't we just can code it like this (put the can_print_it and print_letters functions at the top and remove the need for forward declaration):

#include <stdio.h>
#include <ctype.h>

int can_print_it(char ch)
{
    return isalpha(ch) || isblank(ch);
}

void print_letters(char arg[])
{
    int i = 0;

    for(i = 0; arg[i] != '\0'; i++) {
        char ch = arg[i];

        if(can_print_it(ch)) {
            printf("'%c' == %d ", ch, ch);
        }
    }

    printf("\n");
}

Is there really times when the forward declaration is important and unavoidable?


Solution

  • Forward declarations of functions in C typically have two different uses.

    Modules

    The header of exported functions are declared in a header file which is included in a client module.

    Mutual Recursion

    In mutual recursion two functions call each other repeatedly. Without a forward declaration one of the two functions will be undeclared in the body of the other.

    Example:

    int Odd(int n);
    
    int Even(int n)
    {
        return (n == 0)? 1: Odd(n - 1);
    }
    
    int Odd(int n)
    {
        return (n == 0)? 0: Even(n - 1);
    }
    

    With a function pointer though, we can do without a forward declaration:

    int (*odd)(int n);
    
    int Even(int n)
    {
        return (n == 0)? 1: odd(n - 1);
    }
    
    int Odd(int n)
    {
        return (n == 0)? 0: Even(n - 1);
    }
    
    void Init(void)
    {
        odd = Odd;
        ...
    }