Include Guards In C++ - C++ Programming Tutorial
C++ Course / Miscellaneous / Include Guards In C++

Include Guards In C++

BLUF: Mastering Include Guards In C++ is a critical step in becoming a proficient C++ developer. This lesson provides a deep dive into the syntax, performance considerations, and real-world applications of this concept.
Key Performance Insight: Include Guards In C++

C++ is renowned for its efficiency. Learn how Include Guards In C++ enables low-level control and high-performance computing in the tutorial below.

In this guide, you will discover the concept of include guards in C++ along with illustrative examples.

Include guards are frequently utilized in C++ to prevent the multiple inclusion of a header file within a single translation unit, commonly known as header guards or macro guards. This practice helps prevent duplicate symbol definitions, thereby reducing the likelihood of encountering linker errors.

The directive #define MYHEADERFILEH is responsible for defining the macro MYHEADERFILEH. This action serves to prevent the inclusion of the code enclosed within the #ifndef block if the macro has already been defined.

You should place the header content within the #ifndef and #endif directives. This content represents the actual contents of your header file.

Example

#ifndef MY_HEADER_FILE_H
#define MY_HEADER_FILE_H
// Your header content goes here
#endif // MY_HEADER_FILE_H

endif marks the end of the included guard block.

When the header file is initially included in a translation unit, the MYHEADERFILEH macro is not yet defined, allowing the header content to be included. In subsequent inclusions within the same or different translation units, the MYHEADERFILEH macro is already defined, which stops the content from being included repeatedly.

It is beneficial in preventing problems such as duplicated definitions and declarations that may arise from including a header file multiple times. A standard approach is to employ a macro name derived from the header file's name to guarantee uniqueness. For instance, if your header file is named myheaderfile.h, consider using MYHEADERFILE_H as the include guard macro name.

Modern C++ and technologies such as the C++11 standard brought in the #pragma once directive, which fulfills a similar role as include guards. Nevertheless, #pragma once is not a component of the official C++ standard. To guarantee the highest level of portability and compatibility, it is recommended to stick with conventional include guards.

Program:

Let's consider a scenario to illustrate the purpose of include guards in the C++ programming language.

Example

// Animal.h
#ifndef ANIMAL_H
#define ANIMAL_H
#include <iostream>
#include <string>
class Animal {
    std::string name, color, type;
public:
    void input() {
        name = "Dog";
        color = "White";
    }
    void display() {
        std::cout << name << " is of " << color << std::endl;
    }
};
#endif // ANIMAL_H
// main.cpp
#include "Animal.h"
int main() {
    Animal animal;
    animal.input();
    animal.display();

    return 0;
}

Output:

Output

Dog is of White

Explanation:

  • In this example, the #ifndef ANIMALH and #define ANIMALH create an include guard to prevent the contents of this header file from being included multiple times in the same translation unit.
  • #include and #include<string> the necessary header files for input/output and string manipulation .
  • The Animal class has three private member variables: name, color , and type .
  • Two public member functions are defined within the class:
  • Void input: It sets the name and color attributes to specific values, in this case, "Dog" and "White" .
  • Void display: It prints the values of name and color using std::cout .
  • #endif // ANIMAL_H closes the include guard .

Inside the main function:

  • An instance of the Animal class called animal is created.
  • The input function of the Animal class is called, setting the name and color
  • After that, the display function of the Animal class is called, which prints "Dog is of White" to the standard output.
  • Return 0 indicates the successful execution of the program.
  • The display generates this output function's print statement within the main function.

Complexity Analysis:

Time Complexity:

  • The input and display member functions of the Animal class both have constant time complexity. They perform a fixed number of operations regardless of the input size.
  • The main function calls the input and display functions , each of which has constant time complexity.
  • Overall, the time complexity of this code is O(1) , which means it's constant time complexity.

Space Complexity:

  • The Animal class has three private member variables: name, color , and type . These member variables occupy a constant amount of memory.
  • The Animal object animal is created in the main function and uses a constant amount of memory.
  • The space complexity of this code is also O(1) , which means it uses a constant amount of memory regardless of the input size .
  • In simple terms, the provided code doesn't involve any loops, recursion , or data structures that scale with input size , so both time and space complexities are constant.
  • Program:

Let's consider another instance to grasp the purpose of include guards in C++.

Example

// math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
int add(int a, int b);
int subtract(int a, int b);
#endif // MATH_UTILS_H
// math_utils.cpp
#include "math_utils.h"
int add(int a, int b) {
    return a + b;
}
int subtract(int a, int b) {
    return a - b;
}
// main.cpp
#include <iostream>
#include "math_utils.h"
int main() {
    int x = 10, y = 5;
    int sum = add(x, y);
    int difference = subtract(x, y);
    std::cout << "Sum: " << sum << std::endl;
    std::cout << "Difference: " << difference << std::endl;
    return 0;
}

Output:

Output

Sum: 15
Difference: 5

Explanation:

  • In this example, the #ifndef MATHUTILSH and #define MATHUTILSH lines include guards , which prevent the header from being included more than once in the same translation unit .
  • The two function declarations, int add(int a, int b) and int subtract(int a, int b) , are provided without implementations.
  • It includes the h header file , which contains the function declarations.
  • Here, the implementations of the add and subtract functions are provided. They return the sum and difference of the input integers.
  • It includes the iostream standard header for input/output operations .
  • It also includes the h header file, allowing the use of the add and subtract functions.

Inside the main function:

  • In the main function , two integer variables, x , and y , are declared and assigned values.
  • The add function is called with x and y , and the result is stored in the sum variable.
  • The subtract function is called with x and y , and the result is stored in the difference variable.
  • After that, the results are printed to the console using std::cout .
  • This code demonstrates a modular approach to code organization. The header file h contains function declarations and the implementation file math_utils.cpp provides the actual function implementations.

Complexity Analysis:

Time Complexity:

  • The add and subtract functions in cpp have a constant time complexity, O(1) , as they perform a fixed number of operations ( addition and subtraction ).
  • These functions do not involve loops, recursion , or any operations that scale with input size .
  • The main function in cpp consists of operations, including variable declarations, function calls , and printing .
  • These operations have a constant time complexity, O(1) , as they do not scale with input size.
  • The function calls to add and subtract are constant time operations.
  • The entire codebase contains operations with constant time complexity (O(1)) across all functions and files. As a result, the overall time complexity of the entire program remains O(1) , or constant time complexity.

Space Complexity:

  • The add and subtract functions do not use additional memory that scales with input size .
  • They only use a constant amount of memory for local variables and parameters .
  • Hence, the space complexity of these functions is O(1) .
  • The main function uses a few integer variables ( x, y, sum, difference ) to store results and temporary values.
  • These variables occupy a constant amount of memory regardless of input size.
  • The memory usage does not grow with the input values .
  • Thus, the space complexity of the main function is O(1) .
  • The memory usage across the entire codebase remains constant and does not scale with input size. Therefore, the overall space complexity of the entire program is O(1) , or constant space complexity.
  • Properties:

Include guards in C++ serve as a method to prevent the duplication of a header file within the same translation unit. Their purpose is to guarantee that the contents of a header file are included only once, thus avoiding problems such as redundant symbol declarations and enhancing the structure of the code. The essential characteristics of include guards include:

Prevent Repetitive Inclusions: Implement include guards using conditional preprocessing directives (#ifndef, #define, #endif) to ensure that the contents of the header are included only when the specified macro is not defined. This technique helps avoid the header being included multiple times within the same file.

Header File Protection: To segregate the declarations and definitions in a header file, you can utilize include guards. This technique aids in encapsulating the code and mitigates issues that may occur from repeated inclusions, like redefinition errors.

When naming macros for the included guard, it's important to ensure uniqueness within the header file. A widely accepted practice involves utilizing the uppercase version of the header file's name, where underscores substitute non-alphanumeric characters.

Include guards are a commonly embraced technique endorsed by the majority of C++ compilers. They are portable and aid in maintaining uniform functionality across various platforms and compiler environments.

Header Dependencies: Utilizing include guards also assists in managing dependencies among header files. When multiple headers are included and one relies on the definitions of others, the use of include guards guarantees that these dependencies are managed appropriately.

Input Required

This code uses input(). Please provide values below:

Logic Practice
Install Logic Practice
Add to home screen for a faster app-like experience