Search

2.10 — Introduction to the preprocessor

Translation and the preprocessor

When you compile your code, you might expect that the compiler compiles the code exactly as you’ve written it. This actually isn’t the case.

Prior to compilation, the code file goes through a phase known as translation. Many things happen in the translation phase to get your code ready to be compiled (if you’re curious, you can find a list of translation phases here).

The most noteworthy of the translation phases involves the preprocessor. The preprocessor is best thought of as a separate program that manipulates the text in each code file.

When the preprocessor runs, it scans through the code file (from top to bottom), looking for preprocessor directives. Preprocessor directives (often just called directives) are instructions that start with a # symbol and end with a newline (NOT a semicolon). These directives tell the preprocessor to perform specific particular text manipulation tasks. Note that the preprocessor is not smart -- it does not understand C++ syntax.

The output of the preprocessor goes through several more translation phases, and then is compiled. Note that the preprocessor does not modify the original code files in any way -- rather, all text changes made by the preprocessor happen temporarily in-memory each time the code file is compiled.

In this lesson, we’ll discuss what some of the most common preprocessor directives do.

Includes

You’ve already seen the #include directive in action (generally to #include <iostream>). When you #include a file, the preprocessor replaces the #include directive with the preprocessed contents of the included file, which is then compiled.

Consider the following program:

When the preprocessor runs on this program, the preprocessor will replace #include <iostream> with the preprocessed contents of the file named “iostream”.

Since #include is used to almost exclusively used to include header files, we’ll discuss #include in more detail in the next lesson (when we discuss header files in more detail).

Macro defines

The #define directive can be used to create a macro. In C++, a macro is a rule that defines how input text is converted into replacement output text.

There are two basic types of macros: object-like macros, and function-like macros.

Function-like macros act like functions, and serve a similar purpose. We will not discuss them here, because their use is generally considered dangerous, and almost anything they can do can be done by a normal function.

Object-like macros can be defined in one of two ways:

#define identifier
#define identifier substitution_text

The top definition has no substitution text, whereas the bottom one does. Because these are preprocessor directives (not statements), note that neither form ends with a semicolon.

Object-like macros with substitution text

When the preprocessor encounters this directive, any further occurrence of the identifier is replaced by substitution_text. The identifier is traditionally typed in all capital letters, using underscores to represent spaces.

Consider the following program:

The preprocessor converts the above into the following:

Which, when run, prints the output My name is: Alex.

We recommend avoiding these kinds of macros altogether, as there are better ways to do this kind of thing. We discuss this more in lesson 4.14 -- Const, constexpr, and symbolic constants.

Object-like macros without substitution text

Object-like macros can also be defined without substitution text.

For example:

Macros of this form work like you might expect: any further occurrence of the identifier is removed and replaced by nothing!

This might seem pretty useless, and it is useless for doing text substitution. However, that’s not what this form of the directive is generally used for. We’ll discuss the uses of this form in just a moment.

Unlike object-like macros with substitution text, macros of this form are generally considered acceptable to use.

Conditional compilation

The conditional compilation preprocessor directives allow you to specify under what conditions something will or won’t compile. There are quite a few different conditional compilation directives, but we’ll only cover the three that are used by far the most here: #ifdef, #ifndef, and #endif.

The #ifdef preprocessor directive allow the preprocessor to check whether an identifier has been previously #defined. If so, the code between the #ifdef and matching #endif is compiled. If not, the code is ignored.

Consider the following program:

Because PRINT_JOE has been #defined, the line cout << "Joe" << endl; will be compiled. Because PRINT_BOB has not been #defined, the line cout << "Bob" << endl; will be ignored.

#ifndef is the opposite of #ifdef, in that it allows you to check whether an identifier has NOT been #defined yet.

This program prints “Bob”, because PRINT_BOB was never #defined.

Object-like macros don’t affect other preprocessor directives

Now you might be wondering:

Since we defined PRINT_JOE to be nothing, how come the preprocessor didn’t replace PRINT_JOE in #ifdef PRINT_JOE with nothing?

Macros only cause text substitution for normal code. Other preprocessor commands are ignored. Consequently, the PRINT_JOE in #ifdef PRINT_JOE is left alone.

For example:

In actuality, the output of the preprocessor contains no directives at all -- they are all resolved/stripped out before compilation, because the compiler wouldn’t know what to do with them.

The scope of defines

Directives are resolved before compilation, from top to bottom on a file-by-file basis.

Consider the following program:

Even though it looks like #define MY_NAME “Alex” is defined inside function foo, the preprocessor won’t notice, as it doesn’t understand C++ concepts like functions. Therefore, this program behaves identically to one where #define MY_NAME “Alex” was defined either before or immediately after function foo. For general readability, you’ll generally want to #define identifiers outside of functions.

Once the preprocessor has finished, all defined identifiers from that file are discarded. This means that directives are only valid from the point of definition to the end of the file in which they are defined. Directives defined in one code file do not have impact on other code files in the same project.

Consider the following example:

function.cpp:

main.cpp:

The above program will print:

Not printing!

Even though PRINT was defined in main.cpp, that doesn’t have any impact on any of the code in function.cpp (PRINT is only defined from the point of definition to the end of function.cpp). This will be of consequence when we discuss header guards in a future lesson.


2.11 -- Header files
Index
2.9 -- Naming collisions and an introduction to namespaces

56 comments to 2.10 — Introduction to the preprocessor

  • iamone

    Hey Alex great tutorial!
    i was just wondering why #define Print_joe
    was not just #define joe?
    Doesn't the word Print throw the whole thing off?
    This question has been really bugging me, any answer would be appreciated

    THANKS!

  • prabhakar

    please treat my comment as cancelled prabhakar

  • prabhakar

    i am confused by the explanation, "identifier' and "replacement". u have said [ define identifier replacement ]whereas in the example given to replace 122, i fail to understand this.
    the identifier is YEN_PER_DOLLAR and replacement is 122 as per the define mode GIVEN ABOVE.
    so how can 122 be replaced? by YEN_PER_DOLLAR?

    #define YEN_PER_DOLLAR 122
    int nYen = nDollars * YEN_PER_DOLLAR;

    I AM VERY NEW TO C++ SO BE CONSIDERATE AND EXPLAIN
    THANKS PRABHAKAR

  • Student pairs are assigned a particular area on the grid and then walk through the area, taking detailed notes and looking for specific youth-related opportunities and services. ,

  • William

    First, thank you so much, Alex for your excellent tutorial. Having previously been a developer in Assembler, COBOL and C from the decade of the 80's (left the field in 1990), I can truly appreciate the hard work and excellence you have shared with us all. I find your sight so far to be a wonderful opportunity for me to once again explore the world of programming thru C++.

    My question:
    These last two entries by baldo and Prayrit, baldo indicates that Prayrit's code should be the full example for header guards. Since you did not reply, I assume you do agree.

    I also take note of your explanation that the compiler will check the function prototypes that have been declared via the add.h and subtract.h #includes against the function calls within the source code to resolve any syntactical errors and it will be the job of the linker to ensure that all the function calls are eventually defined.

    Having said all that, I am not quite sure of the purpose of 'mymath.h'. The comment in the header file says "// your declarations here". Is it additional math declarations (eg. division() or multiplication()prototypes)or was it supposed to be the 'definitions' for the add() and subtract() functions. I assumed it to be the latter.

    If mymath.h does in this particular case contain the definitions for add() and subtract(), then when it compiles, wouldn't the compiler not only insert the add() and subtract() function prototypes for declaration within main.cpp but because of the #include of mymath.h within the add.h and subtract.h files, also insert the function definitions of add() and subtract() I assume to be located therin, thereby causing compiling errors?

    Finally, if mymath.h does not contain the definitions, then where are the definitions in this case, and what is mymath.h doing?

  • Prayrit

    I really don't understand the header guard example given here. Would the mymath.h have to be taken out of the add and subtract headers, and then put into the main class with another header guard?

    • Prayrit

      Actually I think I got it. Tell me if I'm right.

      mymath.h

      #ifndef MYMATH_H
      #define MYMATH_H
      
      // your declarations here
      
      #endif
      

      add.h

      #ifndef ADD_H
      #define ADD_H
      
      #include "mymath.h"
      int add(int x, int y);
      
      #endif
      

      subtract.h

      #ifndef SUBTRACT_H
      #define SUBTRACT_H
      
      #include "mymath.h"
      int subtract(int x, int y);
      
      #endif
      

      main.cpp

      #include "add.h"
      #include "subtract.h"
      
      • baldo

        Yes you got it. This should be the full example for header guards.

      • Rukshan

        Hi Alex,

        Thanks for sharing your knowledge. I have question about using headers. In lesson 1.9 you did not use
        #include "add.h" in the header file but when explaining header guards you used "mymath.h" in the header file. I'm sorry I'm confused. What's the point of using "mymath.h" if its not defined.

        regards,
        Rukshan.

      • Rukshan

        Hi,

        Would you kindly write "// your declarations here" part to make it clear. Because I still don't get the use of "mymath.h" here. Thanks a lot.

      • Rukshan

        Would you kindly write “// your declarations here” part to make it clear. Because I still don’t get the use of “mymath.h” here.

        • Trophy

          Wouldn't you not need to add the header guards in add.h and subtract.h since the issue is with mymath.h being called twice and not the other two? Or is this just good form?

      • artxworks

        [sourcecode language="css"]

        //mymath.h

        #ifndef MYMATH_H
        #define MYMATH_H

        // your declarations here

        #endif
        add.h

        #ifndef ADD_H
        #define ADD_H

        #include "mymath.h"
        int add(int x, int y);

        #endif
        subtract.h

        #ifndef SUBTRACT_H
        #define SUBTRACT_H

        #include "mymath.h"
        int subtract(int x, int y);

        #endif
        main.cpp

        #include "add.h"
        #include "subtract.h"
        [/sourcecode]

        I still don't understand the mymath.h thing ... can you give an example to what can be placed inside that header? than can be used by your add and subtract headers ... I understand that by calling the mymath.h on both the add and subtract headers will prevent it being called on twice in the main function but I'm wondering what kind of equation can be placed there ....

      • artxworks

        [sourcecode language="cpp"]

        //mymath.h

        #ifndef MYMATH_H
        #define MYMATH_H

        // your declarations here

        #endif
        add.h

        #ifndef ADD_H
        #define ADD_H

        #include "mymath.h"
        int add(int x, int y);

        #endif
        subtract.h

        #ifndef SUBTRACT_H
        #define SUBTRACT_H

        #include "mymath.h"
        int subtract(int x, int y);

        #endif
        main.cpp

        #include "add.h"
        #include "subtract.h"
        [/sourcecode]

        I still don't understand the mymath.h thing ... can you give an example to what can be placed inside that header? than can be used by your add and subtract headers ... I understand that by calling the mymath.h on both the add and subtract headers will prevent it being called on twice in the main function but I'm wondering what kind of equation can be placed there ....

  • Noha

    Hi Alex,
    In the example you gave about #include "add.h" and #include "subtract.h", where we use #ifdef/#ifndef and #andif?
    I guess it should be in main.cpp but don't know where exactly and how :-/

    • Cooper

      Thanks, Alex! your site is a real help! I wrote a sample temperature converter program with the site's help!

      Noha, will this help?

      #ifndef WRITEANSWER
      #define WRITEANSWER
      
      void WriteAnswer(int x);
      
      #endif
  • csvan

    Alex,

    I think it would be very helpful to add a concrete example of header guards in action at the end of this page, based on the headers you previously declared. As this is a somewhat confusing concept depending on how you approach it, having a concrete, documented example would drive through a very forceful explanation.

    Thanks for all your hard work!

  • Ray

    I have a question about header guards...borrowing from the above examples if we define:

    add.h

    #ifndef ADD_H  
    #define ADD_H  
      
    #include "myMath.h"  
    int add(int a, int b)
    
    #endif
    

    subtract.h

    #ifndef SUBTRACT_H  
    #define SUBTRACT_H  
      
    #include "myMath.h"  
    int subtract(int a, int b)
    
    #endif
    

    and with main.cpp including both:

    #include "add.h"
    #include "subtract.h"
    

    won't we still have the exact same problem, ie add.h and subtract.h both still bring in a copy of myMath.h and the compiler will still complain?

    Thanks,
    Ray

    PS-Thanks for putting this tutorial up, its easily the best I've seen on the web

    • Ray

      Never mind i just figured it out...if we use the header guards for every header, in the above example this will include the myMath.h, then when we try to bring in the myMath.h headera second time, MYMATH_H will already be defined (from the first time it was brought in) and the #ifndef statement will not allow for whatever is in myMath.h to be brought in a second time...thats pretty neat.

      Thanks again
      Ray

      [ You got it. -Alex ]

      • Noha

        I just paid attention that your question is close to the question I posted.
        You say "#ifndef statement will not allow for whatever is in myMath.h to be brought in a second time", you mean that #ifndef MYMATH_H is needed before every #include of add.h and subtract.h?

        • Matt

          The idea is that myMath.h would have a header guard of MYMATH_H, after the first include it would define MYMATH_H and allow the first myMath.h to compile. When it was included the second time MYMATH_H would already be defined from the first call to myMath.h, so it would not compile the second instance of the include.

          tl;dr: The header guard for myMath.h (MYMATH_H) is not needed in add.h or subract.h, it's needed in myMath.h

  • adam

    Why can't you make your whole program in a header file then just have #include "headerfile.h" in the main.cpp and compile? What can and can't you put in a header file instead of a .cpp file?

    • You can put almost anything in a header file (there are a few exceptions). Thus, you could write your whole program in a header file and #include it into a .cpp, but if you're going to do that, why not just skip the header file and put the code in the .cpp in the first place?

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">