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?
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;
...
}
Forward declarations of functions are unavoidable whenever your call graph is cyclic; that is, whenever you have (direct or indirect) recursion between functions.
They are useful if you want to separate your program into more than one translation unit, as they allow separation of declaration and definition of functions (placing the declaration in a .h
header and the definition in a .c
file).
You should declare functions in the order that makes sense. This should be described in the coding style document you follow. One example of common design is:
- h-file with all publically available function declarations.
- c-file with all private function declarations at the top.
- then in the same c-file follows the function definition of the public functions.
- and then at the end of that c-file, the function definition of the private functions.
In addition to style and design concerns, ancient versions of C would start to "make up" function parameters and return types if there was no prototype at all visible before the function call.
Forward declaration is upto the program's need. Programmer can design it in their own.
Understand the significance: In C and C++, the line above represents a
forward declaration of a function and is the function's prototype.
After processing this declaration, the compiler would allow the
program code to refer to the entity printThisInteger in the rest of
the program. The definition for a function must be provided somewhere
(same file or other, where it would be the responsibility of the
linker to correctly match references to a particular function in one
or several object files with the definition, which must be unique, in
another):