CS 70

#include Directives

The Story So Far

With what we've learned, we can now change our original two source files into three source files, where code that's needed by both the original files is moved to its own file.

cowchat.cpp:

#include <iostream> // for std::cin, std::cout
#include <string>   // for std::string

// Declares the printMoos function.
void printMoos(int numMoos);

int main() {
    std::cout << "Chat with a cow!";
    std::string userIn;
    do {
        std::cout << std::endl  // New line
                  << "> ";      // The prompt
        std::getline(std::cin, userIn);
        int nMoos = 1 + userIn.size() % 2;
                     // ^-- Either 1 or 2 moos;
        printMoos(nMoos);
    } while (std::cin.good() && userIn != "");
    std::cout << "\n\nBye!\n";

    return 0;
}

cowmath.cpp:

#include <iostream>

// Declares the printMoos function.
void printMoos(int numMoos);

int main() {
    std::cout << "Cow math!\n";

    std::cout << "Enter the first number: ";
    int x = 0;
    std::cin >> x;

    std::cout << "Enter the second number: ";
    int y = 0;
    std::cin >> y;

    if (std::cin.good()) {
        std::cout << "The cow goes: ";
        printMoos(x + y);
        std::cout << std::endl;
    } else {
        std::cout << "\n\nSomething went wrong!\n";
    }

    return 0;
}

printmoos.cpp:

#include <iostream> // for std::cin, std::cout

// Prints the given number of "moos"
void printMoos(int numMoos) {
    std::cout << "Moo";
    for (int i = 1; i < numMoos; ++i) {
        std::cout << " moo";
    }
    std::cout << ".";
}

How many times do we need to run clang++ in order to compile two executable files, cowchat and cowmath?

We need to run clang++ five times:

  1. clang++ -c printmoos.cpp compiles printmoos.cpp into printmoos.o
  2. clang++ -c cowchat.cpp compiles cowchat.cpp into cowchat.o
  3. clang++ -c cowmath.cpp compiles cowmath.cpp into cowmath.o
  4. clang++ -o cowchat cowchat.o printmoos.o links cowchat.o and printmoos.o to form cowchat
  5. clang++ -o cowmath cowmath.o printmoos.o links cowmath.o and printmoos.o to form cowmath
  • Cat speaking

    This is better. Less code duplication by having only one definition for printMoos.

  • Duck speaking

    But there's still some code duplication: we have two declarations for printMoos.

  • LHS Cow speaking

    Right. The function declaration still appears in multiple files. If the declaration ever changes, we will have to change it everywhere!

  • RHS Cow speaking

    We need a way for cowmath.cpp and cowchat.cpp to share a single copy of the declaration as well! We will accomplish this with a very useful tool…

#include Directives

As we mentioned last lesson, before the compilation process really gets started, the first step is to preprocess the code.

  • The preprocessor's job is to manipulate the text in source files in various ways before they are compiled.
  • You give commands to the preprocessor with preprocessor directives in your code files; these directives start with the character #.
  • The preprocessor executes one directive at a time as it passes over the file.
  • After the preprocessor is finished, the modified code is passed into the compiler.

There are several preprocessor directives, but right now we will focus on a particularly important one: #include.

  • #include is essentially a kind of copy-and-paste.
    • It takes the entire contents of a specified file and inserts it into the including file before compiling.
  • #include "filename" assumes that filename is a file that we have written, and the preprocessor will look for it in the current directory.
  • #include <filename> assumes the file is a file that is part of the C++ system (rather than our code) and will look for it somewhere other than the current directory; typically in some system directory.
  • Dog speaking

    Wait a minute! I've seen #include before!

  • LHS Cow speaking

    Good catch. We've seen #include statements at the top of basically all of our programs so far.

  • Dog speaking

    Ha. “Catch”.

At a high level, what does the line #include <iostream> do?

  • Cat speaking

    That line finds a file named iostream somewhere in the standard library files and then dumps its contents right where it says #include <iostream>.

  • LHS Cow speaking

    Exactly!

  • Hedgehog speaking

    Um, can I ask, how do you pronounce “#include”?

  • LHS Cow speaking

    Short version: # is hash, so it's pronounced hash include.

  • RHS Cow speaking

    Long version: # is the “number sign” character. In many contexts in the USA, it's pronunced “pound”, but in computing contexts (and the rest of the world to avoid confusion with the £ symbol), it is usually pronounced as “hash”. That's where Twitter's “hash tags” come from, they're special tags embedded in posts, indicated with a hash sign. So on Twitter, we might say #inclusivity as “hash-tag inclusivity”, but in C and C++ it's just “hash include”. The symbol dates back to at least the 1850s, and was included on standard typewriter keyboards in 1886. Both when C adopted it for the preprocessor (in 1972) and when first used on Twitter (in 2007), it was probably because it was a symbol on most people's keyboards that was rarely used for anything else.

You can see that we have #include <iostream> in all three files (cowchat.cpp, cowmath.cpp, and printmoos.cpp), which tells the compiler that whatever is in the iostream file is also “in” all three of our .cppfiles.

The good news is that we didn't have to literally make three copies of that code!

  • Dog speaking

    Wait, that gives me an idea! Can we do the same thing with the declaration of printMoo??

  • LHS Cow speaking

    We totally can! Let's do it!

(When logged in, completion status appears here.)