Search

1.9 — Header files

Headers, and their purpose

As programs grow larger and larger (and include more files), it becomes increasingly tedious to have to forward declare every function you want to use that lives in a different file. Wouldn’t it be nice if you could put all your declarations in one place?

C++ code files (with a .cpp extension) are not the only files commonly seen in C++ programs. The other type of file is called a header file, sometimes known as an include file. Header files usually have a .h extension, but you will sometimes see them with a .hpp extension or no extension at all. The purpose of a header file is to hold declarations for other files to use.

Using standard library header files

Consider the following program:

This program prints “Hello, world!” to the console using cout. However, this program never defines cout, so how does the compiler know what cout is? The answer is that cout has been declared in a header file called “iostream”. When we use the line #include <iostream>, we’re requesting that all of the content from the header file named “iostream” be copied into the including file. That makes the content from the header file available for use in our code file.

Keep in mind that header files typically only contain declarations. They do not define how something is implemented. So if cout is only declared in the “iostream” header file, where is it actually defined? It is implemented in the C++ runtime support library, which is automatically linked into your program during the link phase.

Consider what would happen if the iostream header did not exist. Wherever you used std::cout, you would have to manually copy in all of the declarations related to std::cout into the top of each file that used it! This would require knowledge of what’s relevant and what’s not. It’s much easier to just #include iostream!

Writing your own header files

Now let’s go back to the example we were discussing in a previous lesson. When we left off, we had two files, add.cpp and main.cpp, that looked like this:

add.cpp:

main.cpp:

(If you’re recreating this example from scratch, don’t forget to add add.cpp to your project so it gets compiled in).

We used a forward declaration so that the compiler would know what “add” was when compiling main.cpp. As previously mentioned, writing forward declarations for every function you want to use that lives in another file can get tedious quickly.

Header files can relieve us of this burden. A header file only has to be written once, and it can be included in as many files as needed. This also helps with maintenance by minimizing the number of changes that need to be made if a function prototype ever changes (eg. by adding a new parameter).

Writing our own header files is surprisingly easy. Header files consist of two parts.

The first part is called a header guard, which is discussed in the next lesson (on the preprocessor). Header guards prevent a given header file from being #included more than once in the same file.

The second part is the actual content of the .h file, which should be the declarations for all of the functions we want other files to be able to see. Our header files should all have a .h extension, so we’ll call our new header file add.h:

add.h:

In order to use this header file in main.cpp, we have to include it.

main.cpp that includes add.h:

add.cpp stays the same:

When the compiler compiles the #include "add.h" line, it copies the contents of add.h into the current file at that point. Because our add.h contains a function prototype for add(), this prototype is now being used as a forward declaration of add()!

Consequently, our program will compile and link correctly.

Note: When you #include a file, the entire content of the included file is inserted at the point of inclusion.

If you get a compiler error about add.h not being found, make sure the file is really named add.h. Depending on how you created and named it, it’s possible the file could have been named something like “add” (no extension) or “add.h.txt” or “add.hpp”.

If you get a linker error about add() not being defined, make sure you’ve included add.cpp in your project so it compiles properly!

Angled brackets vs quotes

You’re probably curious why we use angled brackets for iostream, and double quotes for add.h. The answer is that angled brackets are used to tell the compiler that we are including a header file that was included with the compiler, so it should look for that header file in the system directories. The double-quotes tell the compiler that this is a header file we are supplying, so it should look for that header file in the current directory containing our source code first. 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 fall back to checking the system directories.

Rule: Use angled brackets to include header files that come with the compiler. Use double quotes to include any other header files.

Header files may include other header files. However, you should never rely on this. Always #include all of the header files you need to use from each .cpp file.

Rule: Each .cpp file should explicitly #include all of the header files it needs to compile.

Why doesn’t iostream have a .h extension?

Another commonly asked question is “why doesn’t iostream (or any of the other standard library header files) have a .h extension?”. The answer is, because iostream.h is a different header file than iostream is! To explain requires a very short history lesson.

When C++ was first created, all of the files in the standard runtime library ended in .h. Life was consistent, and it was good. The original version of cout and cin lived in iostream.h. When the language was standardized by the ANSI committee, they decided to move all of the functions in the runtime library into the std namespace (which is generally a good idea). However, this presented a problem: if they moved all the functions into the std namespace, none of the old programs would work any more!

To try to get around this issue and provide backwards compatibility for older programs, a new set of header files was introduced that use the same names but lack the .h extension. These new header files have all their functionality inside the std namespace. This way, older programs that include #include <iostream.h> do not need to be rewritten, and newer programs can #include <iostream>.

When you include a header file from the standard library, make sure you use the non .h version if it exists. Otherwise you will be using a deprecated version of the header that is no longer supported.

In addition, many of the libraries inherited from C that were still useful in C++ were given a c prefix (e.g. stdlib.h became cstdlib). The functionality from these libraries was also moved into the std namespace to help avoid naming collisions.

However, when you write your own header files, you should give them all a .h extension, since you will not be putting your code in the std namespace.

Rule: use the non .h version of a library if it exists, and access the functionality through the std namespace. If the non .h version does not exist, or you are creating your own headers, use the .h version

Including header files from other directories

Another common question involves how to include header files from other directories.

One (bad) way to do this is to include a relative path to the header file you want to include as part of the #include line. For example:

The downside of this approach is that it requires you to reflect your directory structure in your code. If you ever update your directory structure, your code won’t work any more.

A better method is to tell your compiler or IDE that you have a bunch of header files in some other location, so that it will look there when it can’t find them in the current directory. This can generally be done by setting an “include path” or “search directory” in your IDE project settings.

In Visual Studio, you can right click on your project in the Solution Explorer, and choose “Properties”, then the “VC++ Directories” tab. From here, you will see a line called “Include Directories”. Add your include directories there.

In Code::Blocks, go to the Project menu and select “Build Options”, then the “Search directories” tab. Add your include directories there.

Using g++, you can use the -I option to specify an alternate include directory.

The nice thing about this approach is that if you ever change your directory structure, you only have to change a single compiler or IDE setting instead of every code file.

Can I put function or variable definitions in a header file?

You shouldn’t, as it may cause linker errors. We’ll explain why in the upcoming lesson on header guards.

Declarations are okay.

Header file best practices

Here are a few best practices for creating your own header files.

  • Always include header guards.
  • Do not define variables in header files unless they are constants. Header files should generally only be used for declarations.
  • Do not define functions in header files.
  • Each header file should have a specific job, and be as independent as possible. For example, you might put all your declarations related to functionality A in A.h and all your declarations related to functionality B in B.h. That way if you only care about A later, you can just include A.h and not get any of the stuff related to B.
  • Give your header files the same name as the source files they’re associated with (e.g. grades.h goes with grades.cpp).
  • Try to minimize the number of other header files you #include in your header files. Only #include what is necessary.
  • Do not #include .cpp files.
1.10 -- A first look at the preprocessor
Index
1.8a -- Naming conflicts and the std namespace

440 comments to 1.9 — Header files

  • Lalo

    Hello I was doing the quiz for the first chapter and decide to come back here and I wanted to ask, are header files essentially just a way to facilitate reusing functions in various files? then everything we do with a header file can be done with forward declarations instead right? is the only reason for using header files convenience and organization?

  • Mingrui Zhang

    Hi ALex,
    Just got a little curious about the namespace.
    When the <iostream.h> library is redefined in the std namespace,
    does the implementations are still in the std runtime lib?

    Thank you so much.

  • David

    Hi Alex,

    Thanks for including the "history lesson". It's thoughtful explanations like this that help to demystify a language like C++ for those of us who are coming to it so many years after its inception. Fantastic work you've done on this tutorial, thank you, thank you, thank you!

  • Clapfish

    Hi Alex,

    I've been loving this tutorial so far and really getting into C++ as a result, so thank you for your hard work!

    This is the first lesson where I've come across something that made me wonder, and wasn't really answered in the material (so far as I could see at least), so I thought I'd flag it up.

    When you talk about creating an add.h file, I got slightly lost wondering how best to do that (I'm currently using CodeBlocks). I went through the motions of creating a file like you describe for .cpp files in an earlier lesson, and when it asked whether I want to include it for Compiling and Linking (with check boxes) I wasn't sure what to do. Reading around the topic and some other comments here further, I figured that isn't necessary, and decided to un-check those boxes - indeed the add.h file doesn't appear under my Sources list in the Project like the .cpp files do. As I suspected, everything works fine that way.

    But, it still left me wondering whether that process should be detailed a bit more explicitly, especially since I really appreciate how thorough these lessons have been so far.

    I'd appreciate your thoughts on this!

    All the best, and thanks again.

    • Alex

      In the Management window, make sure that your project is selected. Then in the File menu, choose New > File.... In the New from template dialog that appears, select C/C++ header and click Go. If you get an optional Welcome to the header file wizard dialog, click Next. Now click the ... button underneath the Filename with full path field. In the Select filename file browser that appears, give your header file a name and .h extension. Then click Save. Back on in the C/C++ header wizard dialog, make sure the Add file to active project checkbox is selected, but that the In build target(s) checkboxes are all unselected. Then click Finish.

      I'm in the process of rewriting this lesson, so I'll make sure this gets included in the body of the lesson update.

      • Clapfish

        Hi Alex, thanks for getting back to me!

        That's perfect, just what I felt was missing (so it's great to hear you'll add that to the lesson for future visitors).

        And as you may have noticed, in my haste I made an error mentioning 'Compiling and Linking' in my comment when I meant 'Release and Debug build targets' (unfortunately I couldn't edit the comment when I'd noticed that, so apologies for the inconsistency).

        Best wishes and keep up the excellent work!

  • Shivang

    I have a main file, a definition file and a header. On compiling it gives error - input not found. But the program runs fine. Is there any problem?

  • George

    Followup to my previous comment : I tried changing the header file's name from "division.h" to "divide.h" (goes without saying, i did

    instead in ConsoleApplication1.cpp too). To my surprise, the program linked just fine. Any ideas on why could that be?

  • George

    Ok, so

    Firstly, I made the following header file

    division.h :

    Then made the following program consisting of two files :

    Source.cpp

    ConsoleApplication1.cpp

    When compiling, I'm getting the following errors :

    E0040 : "expected an identifier"    File: division.h   Line: "4"
    E0018 : "expected a ')' "       File: division.h   Line: "4"
    E0065 : "expected a ; "      File: division.h     Line "4"
    C2062 : "type double unexpected"       File : division.h     Line: "4"

    I would really appreciate it if you could enlighten me as to what exactly the problem with my code is. Thank you in advance~

    • Hi George!

      @division is both a preprocessor macro and a function name. The preprocessor macro is defined before the function is declared, so the function cannot be declared. Rename either the header guard or the function.

  • Beginner

    Although it is 2018, I read that using #pragma once is not standard, so I am refraining from using it. When I use the #ifndef, #define, and #endif, I get an error when I include numbers in the name for #ifndef, so I assume when you say "can be any unique name", it means any unique name without numbers? Or is there something I'm missing.

    • Alex

      I'm not aware of any reasons numbers can't be used in preprocessor identifiers. Visual Studio 2017 accepts them, and C++ itself defines several of them.

    • __bs__

      The defined variable can't be _just_ a number or start with a number:

          #define 1 // <- BAD
          #define 1X // <- BAD
          #define X1 // <- OK

      Honestly you shouldn't be afraid of `#pragma once`. There are really two reasons not to:

      a) You are forced to use an ancient (!) compiler.
      b) You are writing code for high performance computing (i.e. supercomputers) and suspect that it might end up on a Cray cluster...

      In both cases you probably know at the start of the project.

  • MorbidPitaya

    Hey!

    Great tutorial! 😛
    Concerning the inclusion of header files from other directories...

    Is using the 'Include Directories' in 'VC++ Directories' (in project properties) the same as directly adding existing header files through the 'Source Files > Add > Existing Item...' function? Furthermore, is the former option limited to header files, or can I do the same with .cpp ones as well?

    Lastly, can I have multiple header files (with unique names) have identical header guards (that is, with identical header guard names, such as ADD_H as seen in the example)?

    Looking forward to learning code)

    • Alex

      > Is using the 'Include Directories' in 'VC++ Directories' (in project properties) the same as directly adding existing header files through the 'Source Files > Add > Existing Item...' function?

      No. Adding an include directory tells the IDE to look there for headers. Adding a header through the Existing Item only adds it to the project, which gives you easy access to view/modify it. It doesn't help the compiler locate it.

      > Furthermore, is the former option limited to header files, or can I do the same with .cpp ones as well?

      C++ files need to be added to your project directly.

      > Lastly, can I have multiple header files (with unique names) have identical header guards (that is, with identical header guard names, such as ADD_H as seen in the example)?

      You _can_, but you risk running into problems if you do. If both headers that define ADD_H are #included into the same scope, the second one won't be included because the header guard will prevent it.

  • DonnieDarko

    I copied the exact code you provided and got this error when compiling my AddWithHeader.cpp(main file) file in both CodeBlock and command prompt as well.

    undefined reference to `add(int, int)'
    collect2.exe: error: ld returned 1 exit status

    and when I'm compiling add.cpp, it is asking for main()
    saying

    undefined reference to `WinMain'

    Please guide me where I'm wrong.

    • nascardriver

      Hi DonnieDarko!

      You need to compile both files at the same time. Assuming you're using g++:

      Other compilers should work similar.

      • DonnieDarko

        Thanks a lot it worked.
        But I have a doubt. we import iostream we do not need to compile it every time we run a program but than why we have to compile user defined header file every time we run a program.

        • nascardriver

          You don't need to compile anything every time you run the program. You only need to compile files when you compile the program.
          System files don't need to be compiled, because your OS stores a precompiled versions of them. If you're using an IDE, Make or CMake you only need to compile the files that were modified since the last compilation.
          Here's a basic CMakeLists.txt to get you started:

          • DonnieDarko

            Thank you so much, nascardriver
            Now I'm getting it.
            When I open my old program in IDE I need to "run" it directly rather than "build and run" that means it is precompiled.
            Build == compilation.
            Run == Execution.

  • Rahul

    Hi Alex, Great Tutorials, Thanku!!
    Is there any android tutorials just like this where i can learn android?

  • hypost

    Great pics!Your tutorials really make my life much easier!

  • Rajsekar

    i named my header file add.h, if i mention this in main like #include "add.h"
    it says "no such file or directory found"...if i see in properties the header name is "../add.h",if i put this name the program compiles but if i use only "add.h" it dosen't...
    someone help me please...I use codeblocks

    • nascardriver

      Hi Rajsekar!

      Sounds like @add.h is in the wrong directory. Make sure it's in the same directory as @main.cpp.

      • Rajsekar

        thank u nascar..i saved that in other directory..now i corrected it, it works fine...

        if i add an empty file and defined functions in that instead of a "source file" it doesn't compile...Y?

  • Me

    I'm having issues with my code (visual studio).
    I have Main.cpp which contains

    I have NewFile.cpp which contains

    and I have NewFile.h which contains

    This is the error I'm getting in the output:
    1>------ Build started: Project: HelloWorld, Configuration: Debug Win32 ------
    1>NewFile.h
    1>Debug\NewFile.obj : warning LNK4042: object specified more than once; extras ignored
    1>HelloWorld.obj : error LNK2019: unresolved external symbol "int __cdecl doubleNumber(int)" (?doubleNumber@@YAHH@Z) referenced in function _main
    1>C:\Users\noahp\source\repos\HelloWorld\Debug\HelloWorld.exe : fatal error LNK1120: 1 unresolved externals
    1>Done building project "HelloWorld.vcxproj" -- FAILED.
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
    What's going wrong here? Thanks.

    • Dima

      Try to add "#pragma once" at the end of "NewFile.h". I've tested your code with this change and it worked.

    • Brian Gaucher

      I think it's because you included a header file inside your header file.

      Main.cpp

      Newfile.h

      You end up include'ing' "stafx.h" twice which is redundant. So it warns you

  • himanshu

    HI Alex!
    Here i need your help please reply.
    I totally confused what we do after
    creating a directory.
    for example you created a directory using g++
    and then what !
    what is the uses of this directory.

    • nascardriver

      Hi himanshu!

      g++ doesn't create a directory, you create it and tell g++ where it is.

      This directory contains header files which you can then include from your other files.

      main.cpp

      [../src/source/] g++ -I ../includes/ apple.cpp main.cpp

      The "-I ../includes/" allows all files to include files that are located in src/includes/.

      • himanshu

        hi
        i does not understand what  you are try to say
        but can we create our own directory

        • Alex

          You can, but you don't need to. And unless you have a specific reason to do so, you probably shouldn't. 🙂

          • himanshu

            Hi!
            Alex

            GOOD MORNING!

            I think you had explained to how to create our own directory.

            But please answer my this question as simple as you can.

            I totally confused what we do after
            creating a directory.
            for example you created a directory using g++ and then how can we call it or its components that it contains.

            AND ONE BONUS QUESTION:

            Difference between header file and directory.

            • Alex

              I don't explain how to create a directory anywhere (how to do so depends on your operating system, not g++). The directories mentioned in the g++ example are using directories that have already been created, not creating them.

              A header file is a C++ file that contains declarations. A directory is a container that is part of a heirarchical file system. See https://www.computerhope.com/jargon/d/director.htm

  • Ishak

    #include <iostream.h> does this include the function definition? I'm confused. what did they move from <iosteam.h> to std namespace that made <iostream.h> not usable? why couldnt they use namespace std on old programs??

    • Ishak

      Also C++ runtime support library, is that namespace std? or am I confusing stuff?

    • Alex

      > #include does this include the function definition?

      Typically not, the definitions are typically only provided as a precompiled library file, which gets linked into your program.

      > what did they move from to std namespace that made not usable?

      All of the declarations were moved from outside the std namespace to inside the standard namespace. This means any code using iostream.h would not work with iostream, as the code doesn't use the std:: prefix as required to access those declarations inside the namespace.

      > why couldnt they use namespace std on old programs??

      You could, but the point of the name change was to make it so you could still compile older programs without having to modify them first.

  • Hema

    In the above example of add.h, add.cpp and main.cpp, is the scope X and Y restricted to add.cpp or are they accessible in main.cpp also?

    • nascardriver

      Hi Hema!

      @x and @y are parameters of @add. They are set by the caller and can only be accessed by @add.
      In the above example @x will be set to 3 and @y will be set to 4, after that only @add can read and change those variables. They disappear when @add returns.
      Function parameters are covered in lesson 1.4a.

  • omar

    hello
    my question what is the main function of header file #include "stdafx.h" ...why we use it? is there any alternative way for it?

  • nascardriver

    Hi Alex!

    I ran into something here and I'm confused whether this is a feature of C++ or a compiler problem.

    other.hpp

    main.cpp

    Now, naturally I'd say this doesn't work. The syntax is all messed up. But it does work. I understand why it works but I can't imagine it's supposed to.
    Tested with g++ and msvc++.
    Removing the closing bracket in main.cpp will cause a compiler error in main.cpp when using g++ or in other.hpp when using msvc++.
    I didn't test things other than a namespace, I guess they behave the same.
    Please tell me this isn't legal C++.

    • Alex

      It's syntactically legal, though rather idiotic. 🙂 Header files don't get compiled directly, they only get compiled when they are included into a .cpp file. So when main.cpp #includes other.hpp, the contents of other.hpp are copied into main.cpp at the point of inclusion (by the preprocessor). Then _that_ is compiled. The compiler has no idea that the closing brace in main.cpp was ever disconnected from the namespace in other.hpp...

      That said, you should never do this. 🙂

Leave a Comment

Put all code inside code tags: [code]your code here[/code]