Search code examples
cc-preprocessorifndef

How does the preprocessor know to translate HEADER_H to header.h?


Per this question, it seems there is some flexibility to how you can write that--

#ifndef _HEADER_H

or:

#ifndef __HEADER___H__

etc. It's not set in stone.

But I don't understand why we're using underscores at all in the first place. Why can't I just write:

#ifndef header.h

What's wrong with that? Why are we placing underscores everywhere and capitalizing everything? What does the preprocessor do with underscores?


Solution

  • header.h is not a valid identifier. You cannot have a period in a macro name.

    That said, the name you pick for your include guard macros is completely arbitrary. After all, it's just another variable. It is purely convention (and reasonable in order to avoid clashes) to name them after the file.

    I encourage you to phrase the header structure out aloud to see what the preprocessor does.

    #ifndef MY_HEADER_H    /* If the macro MY_HEADER_H is not defined (yet)... */
    #define MY_HEADER_H    /* ... then define it now ... */
    
    ...                    /* ... and deal with all this stuff ... */
    
    #endif                 /* ... otherwise, skip all over it and go here. */
    

    You see that this mechanism works equally well if you substitute MY_HEADER_H with I_REALLY_LIKE_BANANAS or whatever. The only requirement is that it be a valid macro identifier and not clash with the name of any other include guard.

    In the above example, the macro is defined empty. That's fine, but it is not the only option. The second line could equally well read

    #define MY_HEADER_H 1
    

    which would then define the macro to 1. Some people do this but it doesn't really add anything and the value 1 is rather arbitrary. I generally don't do this. The only advantage is that if you define it to 1, you can also use #if in addition to #ifdef.

    A final word of caution: Identifiers that start with an underscore or contain two or more consecutive underscore characters are reserved for the implementation and should not be used in user-code. Hence, _MY_HEADER_H and __MY_HEADER__H__ are both unfortunate choices.

    The logic by which the preprocessor finds the correct header file if you say

    #include <myheader.h>
    

    is completely unrelated. Here, myheader.h names a file and the preprocessor will search for it in a number of directories (that usually can e configured via the -I command line option). Only after it has found and opened the file it will go ahead parsing it and thereby, it will eventually find the include guards that will cause it to essentially skip over the file if it has already parsed it before (and the include guard macro is therefore already defined so the first check evaluates to false).