Search

Language Selector

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. Its purpose is to process 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 manipulates text before the compiler runs.

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.

#include "filename" tells the preprocessor to look for the file in 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.

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, note that neither form ends with a semicolon.

Object-like macros with substitution text

Whenever 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.8 -- Literals, symbolic constants, and const variables.

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: when the identifier is encountered by the preprocessor, it is removed and replaced by nothing!

While this might seem useless, it’s actually used more often than the form with substitution text. We’ll discuss why in the next section, on conditional compilation.

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.

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

52 comments to 1.10 — A first look at the preprocessor

  • GovZ

    Hello guys,

    I just wanted to ask if you have enough room for :

    #if defined(macro_name) || defined (macro_name2)

    in this tutorial :) I use this quite a lot in coding. Is this a part of the standard by the way?

    I have read chapter 0 up to this part and plan to read more. Thanks and more power :)

  • GovZ, as far as I know, that is an official part of the preprocessor. You should also be able to use && to test whether multiple symbols are defined at the same time:

    #if defined (symbol_a) && defined (symbol_b)

    I didn’t cover these specific concepts in this tutorial because I don’t even cover what the || and && symbols mean until section 3.6. This is just supposed to be a quick introduction, not a full preprocessor tutorial. :)

    There are quite a few other neat things the preprocessor can do that I don’t (and don’t plan to) cover in this tutorial. If you are interested in learning more, there are quite a few preprocessor documents that are publicly available. Here’s one.

  • billerr

    This might be a dumb question, but what exactly is the purpose of:

    #define [identifier]

    i.e. a #define without any replacement?

    Is it useful mostly in header guards?

    • Mayur B.

      I’m learning programming for small electronic projects which include micro-controllers, and to me object-like macros w/o substitution text are more frequent than the others.
      Here’s an example.

      in above code, if I don’t want to blow buzzer, then I just comment out the line

      There are may be million examples in every domain, but this is the best one I can think of.
      Thanks, Mayur

      • Mayur B.

        EDIT:
        MY_BAD

        CORRECTION:

  • Jason

    I’m not absolutely sure but from what I’ve read here and a book I have, I believe you are correct about it only being for the header guards when there is no replacement.

  • Billerr, You can use such defines for several reasons. Header guards are the primary one. However, it can be useful to define code that only executes when certain #defines have been set. For example, you might do something like this:

    This would only print out nDebugVariable if the program was compiled with the _DEBUG symbol #defined. You might turn this symbol on when compiling a version for development or testing, but turn it off for the release version.

    In a game I wrote, I used a #define to toggle whether the game generated random dungeons (for the release version) or a special debug level (for testing/development). I could toggle between the two by commenting/uncommenting the #define and recompiling.

  • David

    I have a quick question… what is the benefit of using define as opposed to simply initilializing the variable?

    What is the difference between

    and

    • Personally I don’t think there is any reason to use #define this way.

      The only place I use #defines is when #defining symbols to use with #ifdef or #ifndef. You can’t use regular variables for those.

  • Ok the coding you provided for the header guard is going to be VERY helpful. Thanks for that.

  • arvind

    Great Article , Thanks Alex

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

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

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

    • Alex

      Your #define symbols can be whatever you like so long as they follow the normal identifier naming rules. There’s no difference between #define PRINT_JOE and #define JOE and anything else. The word PRINT is meaningless in this context except maybe as a note to the reader.

  • this is just awesome teacher…made programming lot easier..thank u fellows..!

  • Anand

    VERY NICE MATERIAL, LEARNED AND PERFORMED IN FIRST ATTEMPT. THANKS.

  • YamNahar

    At this step
    #define MY_NAME “Alex”
    cout << "Hello, " << MY_NAME << endl;
    i get 2 errors:
    error C2143: syntax error : missing ';' before '<<'
    error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    what's wrong? I did something wrong, or was something wrong?

  • Learner

    #include directives like these are also valid:
    #include “dir/file.h”
    #include “../file.h”

  • Thanks so much for these tutorials. Wish I had found them years ago. So many basic things that I needed to understand the C++ examples I was reading at the time.

    You present at a good level of detail-enough examples, but not too long.

  • nice article….explained well…But there are 14 directives in C++
    1-#define
    2-#elif
    3-#elifdef
    4-#elifndef
    5-#else
    6-#endif
    7-#error
    8-#if
    9-#ifdef
    10-#ifndef
    11-#include
    12-#line
    13-#pragma
    14-#undef
    You have written about few of them.What about others?

    • Alex

      It’s an intro lesson, so I’ve opted not to be comprehensive here in the interest of having the lesson not be overly-long. I’ll take a note that we could use a more comprehensive lesson on the preprocessor. In the meantime, there’s plenty of reference material available on the internet that can explain these things. Once you understand how the preprocessor works and some of it’s basic functions, picking up the other directives shouldn’t be too much of an issue.

  • Paras

    Hi Alex.Thanks for your wonderful lessons. I am very new to programming, I hope I am asking the right question. This is the code I was practising. Here system (“paused”); does not work for some reason. It just blinks and goes away but if I use
    cin.clear();
    cin.ignore(255, ‘n’);
    cig.get();
    works fine.

    Would you please don’t mind to explain? Sorry for the bad English too :-(
    Thanks

    • Alex

      The cin method clears out any queued input, then waits for the user to press a key before proceeding.

      The method of using system(“pause”) (no d on the end of pause) makes a call to the operating system to run the pause executable (if you open a command prompt on Windows, you can type “pause” (no quotes) and see it execute).

      I recommend the cin method because it will work on any operating system.

  • elRaimundo

    Hi and first of all,
    thanks for the great tutorial!
    I have run into a problem trying to compile my project if I add the following preprocessor directives:

    I get the following error in eclipse cdt on the first call to std::cout (I hope I'm using the correct terminology here):
    error: no type named 'cout' in namespace 'std'
    <iostream> is clearly included and I get no complaints about std::cout when its used later in main,
    so what am I missing here?

    • Alex

      The problem here is that lines 5 and 9 are outside of a function, so your compiler is confused because you’re declaring statements somewhere you aren’t supposed to.

      Try copying lines 4 through 10 into your main() function (or another function that main() calls) and it should work fine.

  • BobZ

    Hi, Alex

    Avneet’s question above was a good one.  But perhaps I am the only one on this planet who does not know what is an "object" in the C++ programming sense?  I had someone explain it to me a few years ago and I did not get it then, so I guess I need a very patient explanation………  I did a quick search of the word in the previous few lessons and did not see where you define it anywhere?  I hope you do not object to my question.  :-)

    • Alex

      An object in C++ programming generally refers to a self-contained data structure that includes functions that operate on that data.

      But in the context of these macros, the word object has a different meaning. They’re called object-like macros because the identifiers that are defined look like data objects (e.g. constant variables), as opposed to function-like macros, which look like function calls.

      Don’t get too hung up on this, it’s just a name. :)

  • Essi

    Thanks for this nice tutorials.

    I’m using MS Visual Studio 2015, and I followed the codes in this page, but I get the two linking errors LNK1169:"one or more multiply defined symbols found" and also LNK2005: "_main already defined in main.obj".
    I googled the errors but I couldn’t find the solution. Some suggest that this problem may occur when there is function definition in the header file?
    But this also does not work!! :(

    • Alex

      Sounds like you have function main() defined twice, possible in two different files in your project, or possible in a header file that’s being included in multiple places.

      Make sure you have function main() defined in only one code (.cpp) file in your project.

  • Essi

    Thanks for the quick response.

    I faced another error Error C2084: ‘Function already has a body’. However, I fixed the problem.
    The issue is when building a project, it is always better to keep the project name the same as the cpp file that contains the main() function.
    Thanks again. :)

  • Kevin

    Hey! I made a small program just messing around, and during the last couple lessons I’ve been editing it to make it simpler/easier to read, here it is

    math.h contains

    Anyways, the problem I’m having is when I try to shove playerInput into its own file and put a function prototype, it doesn’t give the inputs (x and y) to main(). It’ll always give me 0 as the output. What am I doing wrong? Does playerInput just have to be within the same file as main()?

    • Alex

      playerInput() can be in a separate file, if you write it correctly. The problem is that you’re using global variables to pass data between functions, which is a bad idea.

      There are ways to fix this so it will do what you want, but honestly, any solution in that regard is putting a band-aid on bad habits.

      You should get rid of x and y as global variables and utilize local variables, parameters, and return values to move the necessary values between the functions.

  • Stanley Delva

    Can you declare variables in a header file for later use?

    • Alex

      You can define variables in a header, though it might not work like you expect. What actually happens is that when you #include the header file in your .cpp file, all of the lines of the header get copied into the .cpp file. So if you’ve defined any variables in the header, they get copied into the .cpp and treated as if you’d defined them in the .cpp file. If the header is #included in multiple .cpp files, each gets their own copy of the variable (which may or may not cause naming conflicts).

      Defining variables in a header is usually undesirable. IMO, the only variables that you should define in a header are constants that you use in your program.

      It is okay to forward declare variables in a header if that makes sense for what you’re doing (we talk about how to do this in chapter 4).

  • Sharaf

    hey, do you mean
    if i have defined bob then if i use #ifndef it will not print it?

  • Marius

    How do we pronounce the ‘#’ symbol here?

    • Alex

      It doesn’t really have a canonical name. Most often I hear it called “pound” (in the US), “number sign”, or “hash/hashtag”.

  • Nyap

    I came across this on Stack Overflow: https://stackoverflow.com/questions/2915546/is-learncpp-com-good-for-beginners
    "Notably, it completely misses an introduction to the STL and the proper use of it. You barely see std::cout and std::string. There’s no mention of <algorithm> that I could see of and no mention of the <vector> or <deque> or <map> which are the most commonly used containers in C++."
    Whats this? D:

    • Alex

      A professional race car driver might look at a drivers education course and criticise it for not teaching you how to drive race cars. But that’s not really the point, is it?

      Some of these criticisms are fair, and have already been addressed in updates made over the last 5 years. Others (e.g. the omission of parts of the STL) miss the mark a bit. The point of this tutorial isn’t to comprehensively cover every corner of the STL (though I’d like to get there someday) -- it’s to teach you how to use the core language mechanics of C++, so that if you want to learn more about the STL (or anything else that builds upon the core mechanics), you’ll be well set up for doing so!

  • Harshul

    Wouldn’t it be a more appropriate define for macro as given by gnu-
    "A macro is a fragment of code which has been given a name. Whenever the name is used, it is replaced by the contents of the macro."

    • Alex

      That definition would be appropriate if macros were strictly substitution-based. But function-like macros do a little more than replacement (even though we don’t recommend their use).

  • Harshul

    Why is their use not recommended, they are fast and capable of doing what small functions are expected to do???

    • Alex

      Function-like macros are full of gotchas and unexpected behavior that that’s avoided by using normal functions, particularly when it comes to side effects.

      Consider:

      Seems harmless, right?

      But if you call it like this:

      You’d expect the result to be 4, but you actually get 6.

      This happens because ++n is copied into the macro before being evaluated, so your output statement becomes “std::cout << (++n) + (++n);" This sort of behavior is avoided using normal functions.

  • 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

  

  

  

six + fifteen =