cincludeheader-filespragmainclude-guards

Understanding headers and include


I am trying to grasp how actually multiple definitions of include files collaborate and sometimes collide. So I have a custom header file file.h, where some functions are declared within an #include guard. Example:

#ifndef FILE_Ariew7OGJknw00
#define FILE_Ariew7OGJknw00

#include <stdlib.h>  //assume minimal

//interfaces of functions

#endif

Now I have several questions.

1. Since #include <stdlib.h> is already included in the header file.h, I don't need to include it in my file.c. Because file.c includes the file.h which includes stdlib.h. However when I include <stdlib.h> after file.h in my .c, it still works properly. Why is that so? Like:

#include <stdio.h>
#include "file.h"
#include <stdlib.h> 
//code

2. Also what happens if I do:

#include <stdio.h>
#include <stdlib.h>
#include "file.h" 
//code

In reality nothing but why isn't file.h definition skipped (or is it?) based on the guards, since the library stdlib is already included.

Lastly, a more general question: Why are #include guards more widespread used than #pragma once even though the latter has several advantages such as:

• less code
• avoidance of name clashes (i.e. FILE_Ariew7OGJknw00)
• improvement in compilation speed


Solution

  • However when I include after file.h in my .c, it still works properly. Why is that so?

    Because the standard headers have include guards too. So when include it multiple either directly in your code or through another source file, it's skipped.

    why isn't file.h definition skipped (or is it?) based on the guards, since the lib is already declared.

    An include guard doesn't do any check whether any headers or included or not. It doesn't care/know what's inside.

    The preprocessor simply checks if the include guard macro FILE_Ariew7OGJknw00 is defined or not. If defined, it's skipped. Otherwise, it's pasted into your soruce file where you included it.

    Why are #include guards more widespread used than #pragma once even though the latter has several advantages

    It's non-standard. So it makes your your code less portable.


    It's not recommended to include other header files in a header file needlessly. You won't see multiple inclusion issues in practice as it'll work as expected due to include guards. There may be legitimate cases where you need to include other headers. For example, if you have a header like:

    /* header.h */
    
    #ifndef MY_HEADER_H
    #define MY_HEADER_H
    
    #include<stdio.h>
    
    struct my_struct {
       size_t len;
       char *s;
    };
    
    void my func(void);
    void my_blah(int);
    
    #endif
    

    Then it becomes necessary to include <stdio.h> to get size_t definition. If you don't then the souce file that includes this header will have to include <stdio.h>. But a header should be to work on its own without forcing the user of it to know all the dependencies.

    As a convention, a header file should only have the declarations and other header inclusions in it should be minimal.