Home > Software design >  What's the purpose of declaring and then defining a function in C language like this?
What's the purpose of declaring and then defining a function in C language like this?

Time:10-26

1 ) Why would we provide the compiler with the same information two times ? 2 ) Isn't it redundant ? 3) When should we follow this rule ? 4) When can we omit this double declaration and definition ?


void fx(void);

void fx ( void ){

   printf("Hello World\n");
}


int main(void)
{

   fx();
  
}

CodePudding user response:

In your case, it is not needed.

But in this case:

double fx(double x);

int main(void)
{
    printf("%f\n", fx(4.0)); 
    printf("%f\n", dx(4.0)); 
}

double fx(double x)
{
    return x * x;
}

double dx(double x)
{
    return x * x;
}
<source>: In function 'main':
<source>:21:20: warning: implicit declaration of function 'dx'; did you mean 'fx'? [-Wimplicit-function-declaration]
   21 |     printf("%f\n", dx(4.0));
      |                    ^~
      |                    fx
<source>: At top level:
<source>:29:8: error: conflicting types for 'dx'; have 'double(double)'
   29 | double dx(double x)
      |        ^~
<source>:21:20: note: previous implicit declaration of 'dx' with type 'int()'
   21 |     printf("%f\n", dx(4.0));

https://godbolt.org/z/6ffWf9xG8

Generally, function prototypes like

double fx(double);

1 ) Why would we provide the compiler with the same information two times ?

Tells the compiler that somewhere in the code or libraries function fx was or will be defined and it takes a double parameter and returns double. The compiler can emit the correct code to call this function, pass the parameters and use the returned value

2 ) Isn't it redundant

In your example it is. It is not if the definition of the function is not known prior to the function call.

  1. When should we follow this rule ?

I have explained it above.

  1. When can we omit this double declaration and definition ?

When function is defined in the same compilation unit and it is defined before the (as position in the .c file) before first call.

CodePudding user response:

A function declaration without a body, like void fx(void); is called a prototype, and its purpose is to inform the compiler that there exists a function with some return type, some name, and optionally some set of parameters that it can expect to find somewhere else during compilation or afterwards when it's time to link. These are part of the language because they allow programmers to design their software modularly.

Declaring a function prototype prevents the compiler from complaining when you call a function that it has not yet seen the definition of, for instance:

#include <stdio.h>
int foo(int in); //Without this the program will not compile

int main(){
  printf("%d\n",foo(7));
}

int foo(int in){
  return in   1;
}

Additionally the first line of the example above says #include <stdio.h> which tells the compiler to include the C-standard io header file. stdio.h containts a prototype of printf which tells it that it will be able to find a function in the form int printf(const char*,...); once it is time to link the program.

Alternatively, you can write separate files "foo.c", "foo.h" and "main.c" for a more modular approach, like so:

main.c

#include <stdio.h>
#include "foo.h"  //Include .h file to get prototype

int main(){
  printf("%d\n",foo(7));
}

foo.h

#ifndef FOO_H
#define FOO_H

int foo(int in); //Prototype of foo()

#endif

foo.c

#include "foo.h"

int foo(int in){ //Declatation of foo()
  return in   1;
}

Then you can compile foo.c into an object file and pass it to the compiler along with main.c like so:

gcc -c foo.c
gcc -o main main.c foo.o

You are not forced to use prototypes if you do not want to, but if you choose not to use them you will be required to declare every function in your program before it is called in another.

CodePudding user response:

1 ) Why would we provide the compiler with the same information two times ?

When C was first designed computers were extremely limited (e.g. RAM measured in KiB and not MiB or GiB, single CPU with < 1 MHz clock instead multiple CPus with > 1 GHz clock, etc). There were many tricks to cope with this (splitting "compiling" into multiple phases, splitting "programs" into multiple compilation units, reading file/s in small pieces so the whole file isn't in RAM, etc).

One of these tricks is to parse the source files in a single pass. This meant that if you do something like this:

int foo(int x) {
    return bar(x);
}

int bar(int x) {
    return x;
}

..the compiler wouldn't have any clue what "bar()" is while its parsing "foo()" (because it won't see "bar()" until later). The solution was declarations - allow the programmer to declare things before they're defined, so the compiler can do a single pass and not get confused by things it hadn't seen yet.

  1. When can we omit this double declaration and definition ?

You can omit the declaration if the compiler will see the definition before that definition is used. For example, this would be fine:

int bar(int x) {
    return x;
}

int foo(int x) {
    return bar(x);
}

2 ) Isn't it redundant ?

It is redundant, but necessary according to the C language specs because it was necessary 50 years ago (to make a compiler practical on "extremely resource constrained" computers); even though it hasn't made sense for 30 years and newer languages don't require it.

  • Related