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). A code file with translations applied to it is called a translation unit.

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 does not understand C++ syntax -- instead, the directives have their own syntax (which in some cases resembles C++ syntax, and in other cases, not so much).

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.

As an aside...

Using directives (introduced in lesson 2.9 -- Naming collisions and an introduction to namespaces) are not preprocessor directives (and thus are not processed by the preprocessor). So while the term directive usually means a preprocessor directive, this is not always the case.


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 contents of the included file. The included contents are then preprocessed (along with the rest of the file), and 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 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.13 -- 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\n" will be compiled. Because PRINT_BOB has not been #defined, the line cout << "Bob\n" 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.

#if 0

One more common use of conditional compilation involves using #if 0 to exclude a block of code from being compiled (as if it were inside a comment block):

The above code only prints “Joe”, because “Bob” and “Steve” were inside an #if 0 block that the preprocessor will exclude from compilation.

This provides a convenient way to “comment out” code that contains multi-line comments.

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:



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 main.cpp). This will be of consequence when we discuss header guards in a future lesson.

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

209 comments to 2.10 — Introduction to the preprocessor

  • Felandyix

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


    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.........?


    • 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:

      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

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


    • 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.


      Not any more.


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

      • himanshu


  • himanshu

    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>c:\users\agencija\documents\visual studio 2005\projects\0110\0110\0110.cpp(11) : error C3861: 'doSomething': identifier not found
    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
    #ifdef myname
        std::cout << "I am Jay " << std::endl;
    #ifndef sayhi

        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
    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 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                    

    #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

  • 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

    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 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


    . 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


    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?


  • Aman


    #include <iostream>

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


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

    int main()
    #define PRINT


        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

    #define PRINT_JOE

    int main()

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

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

    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


    • 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 all code inside code tags: [code]your code here[/code]