Search

1.10 — A first look at the preprocessor

The preprocessor is perhaps best thought of as a separate program that runs just before the compiler when you compile your program. When the preprocessor runs, it simply scans through each code file from top to bottom, looking for directives. Directives are specific instructions that start with a # symbol and end with a newline (NOT a semicolon). There are several different types of directives, which we will cover below.

The preprocessor is not smart -- it does not understand C++ syntax; rather, it simply manipulates text before the compiler runs. The output of the preprocessor is then sent to the compiler. 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.

Includes

You’ve already seen the #include directive in action. When you #include a file, the preprocessor copies the contents of the included file into the including file at the point of the #include directive. This is useful when you have information that needs to be included in multiple places (as forward declarations often are).

The #include command has two forms:

#include <filename> tells the preprocessor to look for the file in a special place defined by the operating system where header files for the C++ runtime library are held. You’ll generally use this form when you’re including headers that come with the compiler (e.g. that are part of the C++ standard library).

#include "filename" tells the preprocessor to look for the file in the directory containing the source file doing the #include. If it doesn’t find the header file there, it will check any other include paths that you’ve specified as part of your compiler/IDE settings. That failing, it will act identically to the angled brackets case. You’ll generally use this form for including your own header files.

Macro defines

The #define directive can be used to create a macro. A macro is a rule that defines how an input sequence (e.g. an identifier) is converted into a replacement output sequence (e.g. some 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, because their use is generally considered dangerous, and almost anything they can do can be done by an (inline) 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 declarations (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 ‘identifier’ is replaced by ‘substitution_text’. The identifier is traditionally typed in all capital letters, using underscores to represent spaces.

Consider the following snippet:

The preprocessor converts this into the following:

Which, when run, prints the output My favorite number is: 9.

We discuss this case (and why you shouldn’t use it) in more detail in section 2.9 -- 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 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. The only conditional compilation directives we are going to cover in this section are #ifdef, #ifndef, and #endif.

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

Consider the following snippet of code:

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 not be compiled.

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

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

Conditional compilation is used quite a bit in the form of header guards. We’ll take a look at those in the next lesson.

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:

The scope of defines

Directives are resolved before compilation, from top to bottom on a file-by-file basis. Once the preprocessor has finished, all directives 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 anything in function.cpp. This will be of consequence in the next lesson on header guards.

Finally, note that directives defined in a header file can be #included into multiple code files. This provides a way for directives to be defined in one place and used in multiple code files. We’ll see an example of this in the next lesson as well.

1.10a -- Header guards
Index
1.9 -- Header files

118 comments to 1.10 — A first look at the preprocessor

  • Felandyix

    Hey!
    Read all your tutorials, and they are great.
    One question here though.
    Instead of using the following:
    #ifndef
    #define

    #endif

    Is it OK to use #pragma once?
    Dont they do the exact same thing? If not, whats the difference?
    I heard somewhere that #pragma once i OS-spesific, and if you wanna make portable code, you should use #ifndef………?

    Sincerely

    • Alex

      I discuss #pragma once in the next lesson. Short answer, you’re better off using explicit header guards even though #pragma once will probably work in most places.

  • My dear c++ Teacher,
    Please let me following question:
    In subsection "Conditional compilation" 2nd paragraph, by "value" I understand "identifier", e.g. PRINT_JOE, PRINT_BOB. Is it correct?
    With regards and friendship.

  • Devender Butani

    I am getting an error message like this.Can you please help me out with this?

  • My dear c++ Teacher,
    Please let me say you that example

    implies suggestion to use japanese money!
    also that by chance I found following program works and outputs 9.

    With regards and friendship.

  • Mike Hong

    In "scope of defines" section, I was wondering is there any specific reason for you to put #include<iostream> in funcition.cpp not main.cpp?
    And I wrote same coding as mentioned above, but my computer did not print out "printing". I am using CLion instead of Visual Studio and just wondering that cout works differently from editors.

    • Alex

      Each code file should include all of the headers that contain declarations for the functionality it is using.

      function.cpp uses std::cout and operator<<, therefore it needs to include iostream itself. If you omit it, the compiler will probably complain it doesn’t know what std::cout is.

      Each code file is compiled separately, and the compiler doesn’t remember anything from the previous file. So if you had included iostream in main.cpp and not in function.cpp, the compiler would not remember that you had done so.

      std::cout should work fine in clion. Perhaps your output window is either closing immediately, or going to a different window than the one you’re looking at?

  • Vlad A

    Hey Alex! You said that "almost anything [function-like macros] can do can be done by an (inline) function.". Then what is something a macro can do but a function can’t?

    • Alex

      The only good use case I can think of for using a function-like macro over a normal function is for implementing asserts. If you’re not familiar with asserts, I cover them here: http://www.learncpp.com/cpp-tutorial/7-12a-assert-and-static_assert/

      Asserts typically display the code file and line of code causing the assert. This can’t be done via a normal function, because calling a function changes the line of code being executed (and maybe the file). And it can’t be done via an inline function because inline functions don’t have access to the line of code or name of the file. But it can be done via the preprocessor.

  • himanshu

    HEY ALEX!
    HERE WHAT I NEED TO
    KNOW:;
    WHAT IS THIS  
    g++ -o main -I /source/includes main.cpp
    AND WHERE TO PLACE IT WHAT IT DO”’


    ‘AND A QUESTION ARE YOU A SOFTWARE ENGINEER?
    AND HOW LONG YOU TAKE TO LEARN C++?
    PLEASE ONE MORE ? YOU ALSO LEARN C++ ONLINE?
    PLEASE ANSWER IT
    WITH DUE RESPECT TO YOU:]

    • Alex

      > g++ -o main -I /source/includes main.cpp

      This tells g++ to compile main.cpp into a program called main, from the command line. If you’re using an IDE, you don’t need to know this.

      > AND A QUESTION ARE YOU A SOFTWARE ENGINEER?

      Not any more.

      > AND HOW LONG YOU TAKE TO LEARN C++? PLEASE ONE MORE ? YOU ALSO LEARN C++ ONLINE?

      I dunno, I learned it a long time ago, before they had online courses.

      • himanshu

        THANK YOU VERY
        MUCH  TO LET ME KNOW ABOUT
        YOUR EXPERIENCE WITH C++?
                  ;
                  ;
        AND FINALLY YOU ARE MY GREAT
                TEACHER.

  • himanshu

    HEY ALEX!
    AM A NEW LEARNER OF THIS LANGUAGE:
    HERE WHAT I WANT TO KNOW
    WHAT IS DIRECTORY AND WHAT ITS FUNCTION!!
    CAN YOU PLEASE REPLY WITH A EXAMPLE ;
    ITS VERY IMPORTANT
    FOR ME………….;)

  • ukijo

    where to put this code? on the header file ??

  • Djordje D.

    I have a promblem on a last example (The scope of defines) , I am getting this  log in an output field:

    1>---- Build started: Project: 0110, Configuration: Debug Win32 ----
    1>Compiling…
    1>stdafx.cpp
    1>Compiling…
    1>0110.cpp
    1>c:\users\agencija\documents\visual studio 2005\projects\0110\0110\0110.cpp(11) : error C3861: ‘doSomething’: identifier not found
    1>function.cpp
    1>c:\users\agencija\documents\visual studio 2005\projects\0110\0110\function.cpp(13) : fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add ‘#include "stdafx.h"’ to your source?
    1>Generating Code…
    1>Build log was saved at "file://c:\Users\Agencija\Documents\Visual Studio 2005\Projects\0110\0110\Debug\BuildLog.htm"
    1>0110 - 2 error(s), 0 warning(s)
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

    What am I doing wrong?

  • Jim Smith

    First of all, thank you for this site! You make the world a better place.

    Now, the boring stuff. This can be ignored by experienced programmers. I was trying to get fancy and created a function called input() that would ask the user for a number and then return that number back to the caller. Then I put this function on a separate file, just as we did with the add() function. To my surprise, the compiler complained about std::cin and std::cout from the input() function despite the fact that I had #include <iostream> in the main.cpp file. I thought the main.cpp file gets compiled first 🙂 Of, course, I put another #include <iostream> in the input.cpp file and everything worked out fine. But I was wondering, isn’t it a waste to use #include <iostream> multiple times? Then I learned about header guards and with a little Google-Fu I even found out about #pragma once, a directive that prevents <iostream> from being included multiple times.

    • Alex

      A few things:
      1) The C++ compiles each file individually. It does not remember anything from files it’s previously compiled. So if you use std::cout in a given file, that file needs to include iostream.
      2) Header guards do _not_ prevent a header from being included into multiple different files. They prevent a header from being included more than once into the same file.

  • trey

    In you example of print, sometimes it really changes the desicision like:

  • JeffFromOhio

    Alex: Hi, not sure if you still maintain this site. When discussing the preprocessor, instead of saying that it makes changes to the text of a file, I think, isn’t it more accurate to say that the preprocessor creates a new temporary file where the contents of the original source file has changes from the preprocessor merged into this ‘working copy’, and then the ‘working copy’ is what actually gets compiled by the compiler, not the original source file?

    The distinction is important because none of the original files (either .cpp or .h files) are ever actually changed. They will be exactly the same after compilation as before, and so this might confuse new programmers.

    • Alex

      Yeah, I can see how this might have been unclear. I’ve updated the lesson text to explicitly indicate that the original code files are not modified. Thanks for the feedback.

  • Jay Ha

    #include "stdafx.h"
    #include <iostream>

    #define anything "hello the world"

    void hi()
    {
        std::cout << "say hi to me" << std::endl;
    }

    int main()
    {

        #ifdef anything
        std::cout << anything << std::endl;

        #endif // anything
    #ifndef myname
    #define myname
    #endif
    #ifdef myname
        std::cout << "I am Jay " << std::endl;
    #endif
    #ifndef sayhi
        hi();
    #endif

        return 0;
    }

    basically, I understand this lesson.
    I am just wondering whether we are going to have more use of #defines in future lessons. Can’t wait to read more.

    • Alex

      In C++, defines are mostly used for header guards and conditional compilation. I talk about both of these shortly. Beyond that, most of what the preprocessor can do isn’t used, because there are better, safer ways to do the same things.

  • My dear c++ Teacher,
    Please let  me say my problem with
    https://www.codechef.com/ide
    I save (by Ctrl-s) code of function.cpp and give this name, but when run main.cpp, output is:

    /home/WBEnb0/cc58Mmhf.o: In function `main’:
    prog.cpp:(.text.startup+0x12): undefined reference to `doSomething()’
    collect2: error: ld returned 1 exit status

    What is going wrong?
    With regards and friendship.

    • Alex

      It looks like codechef may be treating each tab as a separate program, rather than as separate files to be compiled into a single program. If that’s actually the case, then it’s not suitable for compiling programs that use multiple files.

  • My dear c++ Teacher,
    Please let me say that term "preprocessor" is confusing with integrated circuit "processor". So I think term "precompiler" is better fit for it.
    With regards and friendship.

  • My dear c++ Teacher,
    Please let me point out that in example:

    color of first and second comments is same to directives. Is it mean something?
    With regards and friendship.

    • Alex

      The preprocessor line comments being brown instead of green is due to a limitation of the syntax highlighter used on this website.

      All comments in the source code are removed before the preprocessor runs, so there’s no difference between a comment on a preprocessor line or elsewhere.

  • maria

    i was trying to compile the same code as your’s but it is not working…..it shows this error

    g++ -std=c++11 -o main *.cpp                                                                                    
    main.cpp:4:10: error: ‘cout’ in namespace ‘std’ does not name a type                                            
         std::cout << FOO; // This FOO gets replaced with 9 because it’s part of the normal code                    
              ^                                                                                                      
    sh-4.3

    #define FOO 9 // Here’s a macro substitution
    int main()
    {

    #ifdef FOO // This FOO does not get replaced because it’s part of another preprocessor directive
        std::cout << FOO; // This FOO gets replaced with 9 because it’s part of the normal code
    #endif
    }

  • nikos-13

    "When the preprocessor encounters this directive, any further occurrence of ‘identifier’ is replaced by ‘substitution_text’ (excluding use in other preprocessor directives)."
    What do you mean with "(excluding use in other preprocessor directives)" ??????

    And: "when the identifier is encountered by the preprocessor (outside of another preprocessor directive), it is removed and replaced by nothing!"
    What do you mean with "(outside of another preprocessor directive)" ??????

    • Alex

      Preprocessor directives don’t affect other preprocessor directives. So, for example, if you had the following:

      For normal code, any occurrence of FOO (such as the one being std::cout above) would be replaced by 9. However, other preprocessor statements are immune to this text substitution, so the FOO in #ifdef FOO is not replaced.

      I’ve added this bit to the lesson, since it might be helpful for other readers.

  • Anonymous

    Thank you so much Alex, I have learned a lot from your tutorials

  • Ayush Sharma

    The best tutorials I have come across so far…
    My question is do you have similar tutorials for any other language like java or python?
    If yes,please reply and let me know.

  • Daniel

    hi
    thanks alex
    i have reached here since 5 days ago (going a bit slow but i test and learn every bit of it) 🙂

    one question i have is:
    1_i heard by some that C++ is the mother language and you can learn others very fast if you learn C++..true??
    2_i have also seen an extension for C++ named Xamarin (spelled correctly?) that makes you to make android apps and im going to buy it but i wonder that how it works…you code in C++ and it converts them to java??  or a java support for C++??

    • Alex

      Many languages that came after C++ use a similar syntax to C++, so once you know C++, it is a lot easier to learn other languages. I don’t know if I’d say you can learn them fast, but certainly a lot faster than trying to learn them from scratch.
      I’ve never heard of Xamarin before, so I can’t comment on how it works.

  • Alexander Kindel

    I guess I can’t reply to a specific comment without an account? Anyway, in reply to the immediately above:

    That makes more sense. To be fair, nowhere else I looked mentioned that caveat either. There’s one more thing that isn’t clear now, though; from the section on object-like macros without substitution text, I got the impression that the fact that they replace later appearances of their identifiers with nothing is what makes them useful for conditional compilation, but since that mechanic doesn’t affect other preprocessor directives, and the only place the macro’s identifier necessarily reappears in that context is inside other preprocessor directives, it seems that it doesn’t in fact come into play at all there. Is that right?

    • Alex

      There are no accounts on this site. All functionality is available to anonymous users. Just click the reply link next to the comment you want to reply to.

      Object-like macros without substitution text are pretty much never used outside of conditional compilation directives (which are exempt from the substitution effects).

      • Alexander Kindel

        Huh, I could have sworn the reply buttons weren’t there last time. They probably were there, but I did look.

        Does that mean that one could also use an object-like macro with substitution text for conditional compilation (even though the substitution text would be pointless) and it would work just the same?

        Thanks for the clarifications! This is a very helpful site.

        • Alex

          I’d never thought to try it before. So I just tried it with Visual Studio 2015, and it does work (though as you note, the substitution text isn’t used in this case).

  • Alexander Kindel

    You say an object-like macro without substitution text replaces each subsequent appearance of its identifier with nothing. I understand this to mean that in the example under "conditional compilation," the preprocessor changes line 3 from

    to

    . That, in turn, suggests that the specific circumstance under which code after #ifdef is compiled is when there is no identifier after the #ifdef. In that case, I would expect it to also be possible to get rid of the identifier myself, so that the code

    would cause the code after the #ifdef to be compiled, but it seems that having an #ifdef without an identifier in the first place isn’t allowed. Is the preprocessor allowed to cause it to happen, but I’m not?

    • Alex

      No. I realize I didn’t mention in the lesson that object-like macros don’t affect other preprocessor directives. I’ve updated the lesson to mention that.

      So when you #define PRINT_JOE, any occurrences of PRINT_JOE outside of preprocessor directives are removed, but any occurrences of PRINT_JOE inside of preprocessor directives (such as #ifdef PRINT_JOE) are left alone.

      If this weren’t the case, #ifdef would be useless.

  • Olivier

    hey,

    I’m using visual studio 2015 and had some problems with this code.
    Even if I copy pasted it in, it would give 2 errors.

    Could it be that you just have to add ";" after "printing!" and "not printing!" in the function.cpp?

    thnx

  • Aman

    function.cpp:

    #include <iostream>

    void doSomething()
    {
    #ifdef PRINT
        std::cout << "Printing!"
    #endif
    #ifndef PRINT
        std::cout << "Not printing!"
    #endif
    }

    main.cpp:

    void doSomething(); // forward declaration for function doSomething()

    int main()
    {
    #define PRINT

        doSomething();

        return 0;
    }

    If directives defined in one code can’t be used by other then why didn’t we include iostream directive in the main.cpp as we did in function.cpp?

    • Alex

      main.cpp doesn’t use anything in the iostream header, so it doesn’t need to be included.

      However, if main.cpp did print something using std::cout, it would need to #include iostream itself.

  • Abhishek

    HEY guys, i am unable to get the output for this code. What is wrong? Pls explain.
    Codeblocks in main.cpp

    [#include<iostream>
    #define PRINT_JOE

    int main()

    {
    #ifdef PRINT_JOE
    std::cout << "Joe" << endl;
    #endif

    #ifdef PRINT_BOB
    std::cout << "Bob" << endl;
    #endif

    return 0;
    }]

    I am getting this error

    ||=== Build: Debug in Chapter1.10
    (compiler: GNU GCC Compiler) ===|
    s Folder\C++ Programs Practice\Chapter1.10\main.cpp||   In function ‘int main()’:|
    s Folder\C++ Programs Practice\Chapter1.10\main.cpp|8|  error: ‘endl’ was not declared in this scope|
    s Folder\C++ Programs Practice\Chapter1.10\main.cpp|8|  note: suggested alternative:|
    C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\
    mingw32\4.9.2\include\c++\ostream|564|                  note:   ‘std::endl’|
    ||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

  • Strong

    Hi guys . why we #define ADD_H in the following code ? this code is about previous examples . I deleted #define ADD_H and my codes still work , Can you explain exactly what happend when we invoke ( include "add.h") ?

  • Joshua2000B

    Is there a way to set a variable that is available within every function? For example, say I wanted to load a variable from a .txt file and have that variable used within a function that uses that number to produce a new digit? This is basically what I have so far.

    Many File Program.cpp

    test.txt

    • Alex

      Yes, global variables are available to serve this purpose, though most programmers would argue you shouldn’t use them unless necessary. We cover global variables and the reasons they are problematic in chapter 4.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter