Home > Blockchain >  Why should we include header file of a function prototype in the same file that the function is decl
Why should we include header file of a function prototype in the same file that the function is decl

Time:10-24

Might be a stupid (and really simple) question, but I've wanted to try since I don't know where to find an answer for that. I'm realizing some book, and I've started googling something - I was actually kinda curious why, if we have files like these:

file1.c

#include <stdio.h>
#include "file2.h"

int main(void){
    printf("%s:%s:%d \n", __FILE__, __FUNCTION__, __LINE__);
    foo();
    return 0;
}

file2.h

void foo(void);

and

file2.c

#include <stdio.h>
#include "file2.h"

void foo(void) {
    printf("%s:%s:%d \n", __FILE__, __func__, __LINE__);
    return;
}

compiling it with:

gcc file1.c file2.c -o file -Wall

Why is it a good practice to include the header file of file2.h which contains prototype of the foo function in the same file that foo is declared? I totally understand attaching it to file1.c, while we should use the header file to define the interface of each module, rather than writing it "raw", but why attaching header file with the prototype to the file where it is declared (file2.c)? -Wall option flag also does not say anything if I won't include it, so why people say it is "the correct way"? Does it help avoiding errors, or is it just for clearer code?

Those code samples are taken from this discussion: Compiling multiple C files in a program

Where some user said it is 'the correct way'.

CodePudding user response:

To answer this question, you should have a basic understanding of the difference between the compiler and the linker. In a nuttshell, the compiler, compilers each translation unit (C file) alone then it's the linker's job to link all the compiled files together.

For instance, In the above code the linker is the one who is searching where the function foo() called from main() exists and links to it.

The compiler step comes first then the linker.

Let's demonstrate an example where including file2.h in file2.c comes handy:

file2.h
void foo(void);
file2.c
#include <stdio.h>
#include "file2.h"

void foo(int i) {
    printf("%s:%s:%d \n", __FILE__, __func__, __LINE__);
    return;
}

Here the prototype of foo() is different from its definition.

By including file2.h in file2.c so the compiler can check whether the prototype of the function is equivalent to the definition of it, if not then you will get a compiler error.

What will happen if file2.h is not included in file2.c?

Then the compiler won't find any issue and we have to wait until the linking step when the linker will find that there is no matching for the function foo() called from main() and it will through an error.

Why bother then if the linker, later on, will find out the error anyway?

Because in big solutions there might be hundreds of source codes that take so much time to be compiled so waiting for the linker to raise the error at the end will waste a great amount of time.

CodePudding user response:

C doesn’t mangle symbols usually (there are some exceptions eg. on Windows). Mangled symbols would carry type information. Without it, the linker trusts that you didn’t make mistakes.

If you don’t include the header, you can declare the symbol to be one thing, but then define it to be whatever else. Eg. in the header you might declare foo to be a function, and then in the source file you can define it to be a totally incompatible function (different calling convention and signature), or even not a function at all – say a global variable. Such a project may link but won’t be functional. The error may be in fact hidden, so if you don’t have solid tests in place, you won’t catch it until a customer lets you know. Or worse, there’s a news article about it.

In C the symbol carries information about its type, so if you declare one thing and then define something with same base name but an incompatible type, the linker will refuse to link the project, since a particular symbol is referenced but never defined.

So, in C you include the header to prevent mistakes that the tools can’t catch, that will result in a broken binary. In C , you do it so that you’ll get perhaps an error during compilation instead of later in the link phase.

CodePudding user response:

This is The Only True ReasonTM:

If the compiler encounters a call of a function without a prototype, it derives one from the call, see standard chapter 6.5.2.2 paragraph 6. If that does not match the real function's interface, it's undefined behavior in most cases. At best it does no harm, but anything can happen.

Only with a high enough warning level, compilers emit diagnostics like warnings or errors. That's why you should always use the highest warning level possible, and include the header file in the implementation file. You will not want to miss this chance to let your code being checked automatically.

  • Related