Skip to content

Instantly share code, notes, and snippets.

@FallenDeity
Last active March 25, 2023 20:12
Show Gist options
  • Save FallenDeity/95b637384e6b43d991b46040799bfca5 to your computer and use it in GitHub Desktop.
Save FallenDeity/95b637384e6b43d991b46040799bfca5 to your computer and use it in GitHub Desktop.
C++ cheat sheet containing all concepts from basics to advanced in order

Contents

Introduction

  • All C/C++ programs must have a main() function.
  • A function named main (lower case only). When a cpp program is executed it executes all statements in main in sequential order.
// library imported to acess in built input and output functions such as cout and cin
#include <iostream>

// special function main int stands for integer and signifies the return type of the function
int main(){
    // printing out a phrase '\n' is a newline character to move
    std::cout << "Hello, World!\n";
    // returning 0 which is an integer :p as we specified int as return type
    return 0;
}

What std:: here stands for?

Comments

In c++ there are single line comments // and multi line comments /*. Comments are not compiled by the compiler and usually exists for notes and instructions for ourselever or other developers making our intentions clear.

Single Line Comment

// This is a single line comment

Multi Line Comment

/*
Line 1
Line 2
And thats it
*/

Note
You can put single line comment into multiline comment. But you cannot nest mutliline comments in another multiline comment.

// VALID
/*
My multi
line
// comment
*/

// INVALID
/* This is another comment /* and another one */ this part is actually not a comment */

Variables

All computers have memory, called RAM, that is available for your programs to use. You can think of RAM as a series of numbered mailboxes that can each be used to hold a piece of data while the program is running. A single piece of data, stored in memory somewhere, is called a value. In C++ direct access to this memory is discouraged unlike older langauges like BASIC. So unlike before like get the value from mailbox 752 we can say get the value from this object. A named object is a Variable and the name is an Identifier.

int x;  // A variable named x is declared of type int

Note
When the program is run the variable will be instantiated ie a fancy abbreviation of saying the object will be created and assigned a memory address to the memory which was allocated for this object.

Click to read more about data types and slightly more advanced stuff

Data Types

A data type tells the compiler what type of value (e.g. a number, a letter, text, etc…) the variable will store.

Note
The data type of a variable cannot be changed after it has been declared.

Inbuilt/Primitive Data Types

As the name suggests these are the data types that are built into the language. These are the basic building blocks of the language. These are the data types that are used to create more complex data types.

Data Type Description Size Range
bool Boolean value 1 byte true or false
char Character 1 byte -128 to 127 or 0 to 255
int Integer 4 bytes -2,147,483,648 to 2,147,483,647
float Floating point number 4 bytes 3.4e−038 to 3.4e+038
double Floating point number 8 bytes 1.7e−308 to 1.7e+308
void No value - -
wchar_t Wide character 2 bytes 0 to 65,535

Note
The size of the data types may vary depending on the compiler and the operating system.

bool isHappy = true;
char letter = 'a';
int age = 21;
float pi = 3.14;
double bigPi = 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912;
void nothing = null;
wchar_t wideChar = L'x';  // L is a prefix to tell the compiler that the character is wide

Derived Data Types

These are the data types that are created using the inbuilt data types. These are more complex data types.

Data Type Description
array An array is a collection of variables of the same type.
pointer A pointer is a variable that stores the memory address of another variable.
reference A reference is an alias for another variable.
function A function is a group of statements that together perform a task.
int arr[5];  // An array of 5 integers
int *ptr;  // A pointer to an integer
int &ref = x;  // A reference to an integer
int func(int a, int b);  // A function that takes two integers and returns an integer

Abstract/User Defined Data Types

These are the data types that are created by the user. These are more complex data types.

Data Type Description
class A class is a user-defined data type that can contain data members and member functions.
struct A struct is a user-defined data type that combines objects of different data types.
union Similar to a struct but all members share the same memory location.
enum An enum is a user-defined data type that consists of integral constants.
typedef A typedef is a user-defined data type that is an alias for another data type.
class Person {
  public:
    string name;
    int age;
    void sayHello() {
      cout << "Hello, my name is " << name << " and I am " << age << " years old." << endl;
    }
};

struct Point {
  int x;
  int y;
};

union Data {
  int i;
  float f;
  char str[20];
};  // size of union is the size of the largest member here it is 20 bytes

enum Color {
  RED,
  GREEN,
  BLUE
}; // RED = 0, GREEN = 1, BLUE = 2

typedef int feet;

Type Modifiers

These are the keywords that are used to modify the data types.

Modifier Description
signed The signed modifier is used to specify that a variable can hold both positive and negative values.
unsigned The unsigned modifier is used to specify that a variable can hold only positive values.
short The short modifier is used to specify that a variable is a short integer.
long The long modifier is used to specify that a variable is a long integer.
signed int i;
unsigned int j;
short int k;
long int l;

Note
No need to fuss or worry about the above data types. Just remember that there are 3 types of data types inbuilt, derived and abstract. And that's it. We will cover each of these data types in detail and more in the upcoming chapters. The above table is just for reference and to give you an idea of what is there in the language.

Initialization

A variable can be initialized at the time of declaration. This means that a variable can be assigned a value at the time of its declaration. The value used to initialize a variable is called the initializer.

int x;  // no initializer (x is uninitialized)
int y = 5;  // initializer is 5 (copy initialization)
int z(5);  // initializer is 5 (direct initialization)

// List initialization (since C++11)
int a{5};  // initializer is 5 (uniform initialization)
int b = {5};  // initializer is 5 (copy list initialization)
int c{};  // initializer is 0 (value initialization)

Note
Copy initialization is also used whenever values are implicitly copied from one variable to another. For example, when a function returns a value, the returned value is copied to the variable that is used to store the return value. This is called copy initialization.

Note
Direct initialization is also used when values are explicitly cast from one type to another.
Try to avoid direct initialization as much as possible since it cause ambiguity and confusion in code. For example, it makes it difficult to distinguish between a function declaration and a variable

int x(); // forward declaration of function x
int x(5); // direct initialization of variable x with value 5

Modern way of initializing variables is to use list initialization also known as uniform initialization or brace initialization. This is the recommended way of initializing variables. It has the following advantages:

  • It is more readable and understandable.
  • It does not allow narrowing conversions.
int x{6.9};  // error: narrowing conversion from double to int

Initialization of Multiple Variables

Multiple variables can be initialized in a single statement.

int x { 5 }, y { 6 }, z { 7 };

Note
Modern compilers will typically generate warnings if a variable is initialized but not used (since this is rarely desirable). And if treat warnings as errors is enabled, these warnings will be promoted to errors and cause the compilation to fail.

int main() {
  int x { 5 };  // warning: unused variable 'x'
  return 0;
}

To avoid this, you can use the [[maybe_unused]] attribute to suppress the warning. Since C++17, this attribute is part of the language and can be used to suppress warnings about unused variables.

int main() {
 [[maybe_unused]] int x { 5 };
 return 0;
}

Uninitialized Variables

Unlike other programming languages, C++ does not initialize variables to a default value. This means that if a variable is declared but not initialized, it will contain garbage data. This is called an uninitialized variable.

#include <iostream>

int main() {
  int x;
  std::cout << x << std::endl;  // garbage value
  return 0;
}

Undefined Behavior

Undefined behavior is a behavior of a program that is not defined by the language specification. This means that the behavior of the program is not specified by the language specification and can vary from one compiler to another. This can lead to unexpected results and can cause the program to crash.

Symptoms of undefined behavior:

  • Produces different results each time the program is run.
  • Incorrect results.
  • Inconsistent behavior sometimes correct and sometimes incorrect.
  • Program crashes either immediately or after some time.
  • Different results on different compilers.
  • Different results on different platforms (operating systems).

Input and Output

C++ provides a set of built-in functions to perform input and output operations. These functions are defined in the iostream header file.

#include <iostream>

std::cout

std::cout is an object of std::ostream class. It is used to display output on the standard output device which is usually the monitor. It allows us to insert data into the output stream.

What is a stream?

A stream is a sequence of characters. It is a sequence of bytes that are sent to or received from a device. Meaning in the case of std::cout it is a sequence of bytes that are sent to the monitor a set of them are displayed at a time. So it is similar in priciple to a movie. A movie is a sequence of frames that are sent to the monitor and displayed one after the other and they wait for a certain amount of time and then the next frame is displayed and so on.

cout -> character output

#include <iostream>

int main() {
  std::cout << "Hello World!";
  return 0;
}

<< is the insertion operator. It is used to insert data into the output stream.

std::endl

std::endl is an object of std::ostream class. It is used to insert a new line character into the output stream and flushes the stream.

endl -> end line

  • It helps indicate the end of a line similar to . in a sentence.
  • It positions the cursor at the beginning of the next line.
  • It flushes the stream.
#include <iostream>

int main() {
  std::cout << "Hello World!" << std::endl;
  return 0;
}

Is std::endl necessary?

std::endl is not necessary. It is used to flush the stream. But flushing the stream is not necessary. It is done periodically by the operating system. So it is not necessary to use std::endl to flush the stream. Hence it is not necessary to use std::endl to insert a new line character.

#include <iostream>

int main() {
  std::cout << "Hello World!\n";
  return 0;
}

std::cin

std::cin is an object of std::istream class. It is used to read input from the standard input device which is usually the keyboard. It allows us to extract data from the input stream.

cin -> character input

#include <iostream>

int main() {
  int x { };
  std::cin >> x;
  return 0;
}

>> is the extraction operator. It is used to extract data from the input stream.

Note
An enter key press is always required after the input is entered.

Keywords and Identifiers

Keywords

Keywords are reserved words that have a predefined meaning in the language. They cannot be used as identifiers or variable names. C++ has a reserved set of 92 keywords as of C++20.

Reserved Keywords

Identifiers

An identifier is a name used to identify a variable, function, class, module, or any other user-defined item.

  • It cannot be a keyword.
  • It can be a combination of letters, digits, and underscores (_).
  • It must start with an alphabet or an underscore (_).
  • It is case sensitive.

Best Practices

  • Use meaningful names.
  • Use camelCase for function names.
  • Use PascalCase for class names.
  • Use snake_case for file names.
  • Use UPPER_CASE for constants.
  • Use LOWER_CASE for variables.

Literals and Operators

Literals

A literal is a notation for representing a fixed value in source code. Literals are represented directly in the source code and are not stored in memory.

#include <iostream>

int main() {
  std::cout << 5;  // 5 is a literal
  return 0;
}

Operators

An operator is a symbol that tells the compiler to perform specific mathematical or logical manipulations.

Arithmetic Operators

Operator Description
+ Addition
- Subtraction
* Multiplication
/ Division
% Modulus
#include <iostream>

int main() {
  std::cout << 5 + 2 << std::endl;  // 7
  std::cout << 5 - 2 << std::endl;  // 3
  std::cout << 5 * 2 << std::endl;  // 10
  std::cout << 5 / 2 << std::endl;  // 2
  std::cout << 5 % 2 << std::endl;  // 1
  return 0;
}

Assignment Operators

Operator Description
= Assigns values from right side operands to left side operand
+= Add AND
-= Subtract AND
*= Multiply AND
/= Divide AND
%= Modulus AND
#include <iostream>

int main() {
  int x { 5 };
  x += 2;  // x = x + 2
  std::cout << x << std::endl;  // 7
  x -= 2;  // x = x - 2
  std::cout << x << std::endl;  // 5
  x *= 2;  // x = x * 2
  std::cout << x << std::endl;  // 10
  x /= 2;  // x = x / 2
  std::cout << x << std::endl;  // 5
  x %= 2;  // x = x % 2
  std::cout << x << std::endl;  // 1
  return 0;
}

Comparison Operators

Operator Description
== Checks if the values of two operands are equal or not, if yes then condition becomes true.
!= Checks if the values of two operands are equal or not, if values are not equal then condition becomes true.
> Checks if the value of left operand is greater than the value of right operand, if yes then condition becomes true.
< Checks if the value of left operand is less than the value of right operand, if yes then condition becomes true.
>= Checks if the value of left operand is greater than or equal to the value of right operand, if yes then condition becomes true.
<= Checks if the value of left operand is less than or equal to the value of right operand, if yes then condition becomes true.
#include <iostream>

int main() {
  std::cout << (5 == 2) << std::endl;  // 0
  std::cout << (5 != 2) << std::endl;  // 1
  std::cout << (5 > 2) << std::endl;  // 1
  std::cout << (5 < 2) << std::endl;  // 0
  std::cout << (5 >= 2) << std::endl;  // 1
  std::cout << (5 <= 2) << std::endl;  // 0
  return 0;
}

Logical Operators

Operator Description
&& Logical AND
Logical OR
! Logical NOT
#include <iostream>

int main() {
  std::cout << (true && true) << std::endl;  // 1
  std::cout << (true && false) << std::endl;  // 0
  std::cout << (false && true) << std::endl;  // 0
  std::cout << (false && false) << std::endl;  // 0
  std::cout << (true || true) << std::endl;  // 1
  std::cout << (true || false) << std::endl;  // 1
  std::cout << (false || true) << std::endl;  // 1
  std::cout << (false || false) << std::endl;  // 0
  std::cout << !true << std::endl;  // 0
  std::cout << !false << std::endl;  // 1
  return 0;
}

Bitwise Operators

Operator Description
& Bitwise AND
Bitwise OR
^ Bitwise XOR
~ Bitwise NOT
<< Bitwise left shift
>> Bitwise right shift
#include <iostream>

int main() {
  std::cout << (5 & 2) << std::endl;  // 0
  std::cout << (5 | 2) << std::endl;  // 7
  std::cout << (5 ^ 2) << std::endl;  // 7
  std::cout << (~5) << std::endl;  // -6
  std::cout << (5 << 1) << std::endl;  // 10
  std::cout << (5 >> 1) << std::endl;  // 2
  return 0;
}

Increment and Decrement Operators

Operator Description
++ Increment
-- Decrement
#include <iostream>

int main() {
  int x { 5 };
  std::cout << x++ << std::endl;  // 5
  std::cout << x << std::endl;  // 6
  std::cout << ++x << std::endl;  // 7
  std::cout << x << std::endl;  // 7
  std::cout << x-- << std::endl;  // 7
  std::cout << x << std::endl;  // 6
  std::cout << --x << std::endl;  // 5
  std::cout << x << std::endl;  // 5
  return 0;
}

Ternary Operator

The ternary operator is the only operator that takes three operands.

#include <iostream>

int main() {
  int x { 5 };
  int y { 2 };
  std::cout << (x > y ? x : y) << std::endl;  // 5
  return 0;
}

Note: For operators such as = or << we call for their effect to be applied to the left operand.

// For example x = y = 9 is equivalent to:
x = (y = 9);  // 9 is assigned to y and then y is assigned to x
std::cout << "Hello" << "World"; evaluates to: (std::cout << "Hello") << "World"; and (std::cout << "Hello") returns a reference to std::cout, so the expression evaluates to std::cout << "World";

Final Note

Note
New programmers often attempt to write the whole program at once and get overwhelmed by numerous errors. This is why it is important to write small programs and test them as you go along. This will help you to identify and fix errors as you go along. It is also important to write programs that are easy to understand. This will help you to debug your programs easily. It is recommended to print out the output of your programs as you go along. This will help you to identify errors easily.

⏭️ Next 🔝 Top

Contents

Functions

What is a function?

A function is a reusable block of code that performs a specific task. Functions are used to avoid repetition of code. Functions are also used to make code more readable and easier to maintain. As you probably already know, that in C++ a function named main contains all the executable code. However, as programs get larger, it is often useful to divide the code into smaller and more manageable blocks. This is where functions come in.

Syntax

returnType functionName( parameter list ) {  // function header containing return type, name and parameters
   body of the function  // function body containing statements to be executed sequentially
}

Example

#include <iostream>

void bar() {  // function definition
    std::cout << "bar() called!";
}

void foo() {  // function definition
    bar();  // a function can be called inside another function
    std::cout << "foo() called!";
}

int main() {
    foo();  // function call
    foo();  // function call again a function can be called multiple times
    return 0;
}

Note

  • The function bar() is called inside the function foo(). The function foo() is called inside the function main(). The function main() is called when the program is executed.
  • As a sidenote a function cannot be nested inside another function.
// Invalid function definition
void foo() {
    void bar() {  // error: nested function 'bar' declared 'static'
       std::cout << "bar() called!";
    }
}

Function returing a value

A function can return a value to the caller. The return type of the function is specified in the function header. The return statement is used to return a value from a function. Now it is not necessary that a function must return a value. If a function does not return a value, then the return type of the function is void.

Syntax

returnType functionName( parameter list ) {  // function header containing return type, name and parameters
   body of the function  // function body containing statements to be executed sequentially
   return value;  // return statement
}

Example

#include <iostream>

int getInteger() {  // function definition
    int a { };
    std::cout << "Enter an integer: ";
    std::cin >> a;
    return a;  // return statement
}

int main() {
    std::cout << "You entered: " << getInteger();  // function call
    return 0;
}
#include <iostream>

void printInteger(int x) {  // function definition
    std::cout << "You entered: " << x;  // no return statement
}

int main() {
    int num { };
    std::cout << "Enter an integer: ";
    std::cin >> num;
    printInteger(num);  // function call
    return 0;
}

Revising the main function

Now lets look back at the main() function. The main() function is the entry point of a C++ program.

int main() {
    // statements
    return 0;
}

Note that how we return 0 here this is to indicate that the program ran successfully. If we return any other value then it indicates that the program did not run successfully. This is a convention followed by most of the C++ programs. A non-zero return value is usually used to indicate an error. For example, if we return 1 then it indicates that the program encountered an error.

Strictly speaking by C++ standards, there are 3 status codes that can be returned by the main() function.

  • 0: Indicates that the program ran successfully.
  • EXIT_SUCCESS: Indicates that the program ran successfully.
  • EXIT_FAILURE: Indicates that the program encountered an error.
#include <cstdlib>  // for EXIT_SUCCESS and EXIT_FAILURE macros

int main() {
    // statements
    return EXIT_SUCCESS;
}

Note

  • Make sure functions with a return type other than void have a return statement. If a function does not have a return statement, is usually causes undefined behavior.
  • Function main() implicitly returns 0 if it does not have a return statement.
  • Functions can only return one value. There are ways to return multiple values from a function, but we will discuss them later.

Function Parameters

A function can take parameters. Parameters are variables that are passed to the function. These parameters are used inside the function to perform some task.

Say we want to write a function that takes two integers and returns their sum. We can do this by passing the two integers as parameters to the function.

#include <iostream>

// parameters x and y of data type int
int add(int x, int y) {  // function definition
    return x + y;  // return statement
}

int main() {
    int a { }, b { };
    std::cout << "Enter two integers: ";
    std::cin >> a >> b;
    std::cout << "Sum: " << add(a, b);  // function call
    return 0;
}

Forward Declaration

A forward declaration is a declaration of a function before its definition. Forward declarations are used to tell the compiler that a function exists and will be defined later in the program. This is useful when a function is called before its definition.

#include <iostream>

int add(int x, int y);  // forward declaration

int main() {
    int a { }, b { };
    std::cout << "Enter two integers: ";
    std::cin >> a >> b;
    std::cout << "Sum: " << add(a, b);  // function call
    return 0;
}

int add(int x, int y) {  // function definition
    return x + y;  // return statement
}

Note

  • A forward declaration is not a definition. It is just a declaration. A function definition is a function declaration with a function body.
  • On a sidenote as best practice, it is recommended to include variable names in the function declaration. This makes it easier to understand the function.
int add(int x, int y);  // forward declaration
int add(int, int);  // forward declaration without variable names

Definition vs Declaration

A declaration is a statement that tells the compiler about the existence of an identifier and its type.

int add(int x, int y);
int x;

A definition tells the compiler how an idetifier is implemented or where that identifier must be instantiated. A definition must be preceded by a declaration.

int add(int x, int y) {
    return x + y;
}

A declaration is not a definition but a definition is a declaration.

Scopes

A scope is a region of a program where a variable is defined. A variable can be accessed only within its scope. When an identifier cannot be seen, we cannot use it, and it is said to be out of scope. Scope is a compiler concept, not a runtime concept.

Local Scope

A variable declared inside a function is called a local variable. Local variables are only accessible within the function where they are declared. Local variables are created when the function is called and destroyed when the function is exited.

In definition:

  • A local variable variables scope begins at the point of variable declaration and ends at the end of the block/curlies in which it is declared.
#include <iostream>

void foo() {
    // x cannot be used anywhere yet since it is declared after this line
    int x { 10 };  // local variable entered scope
    std::cout << x;  // x can be used here
}  // x goes out of scope here

int main() {
    foo();
    return 0;
}

Out of Scope vs Going out of Scope

  • Out of scope: An identifier is out of scope if it cannot be seen and used in the program.
  • Going out of scope: This is used on objects rather than identifiers. An local variables lifetime ends when it goes out of scope. This means that the object is destroyed and the memory is freed.

Note

  • Lifetime is a runtime concept, while scope is a compiler concept.

Global Scope

A variable declared outside of all functions is called a global variable. Global variables are accessible from anywhere in the program. Global variables are created when the program starts and destroyed when the program ends.

#include <iostream>

constexpr int g_x { 10 };  // global variable

void foo() {
    std::cout << g_x;  // g_x can be used here
}

int main() {
    foo();
    return 0;
}

Note
Using non-constant global variables is generally not a good idea because it makes the program difficult to debug and maintain as it is difficult to keep track of all the places where the variable is used and modified. It also reduces the modularity of the program.
g_ is a common prefix used for global variables to prevent name collisions and to make it clear that the variable is global.

Namespaces

Lets say for example your friend asked you to visit the supermarket and buy a product named milk. You go to the supermarket and you see a lot of products with the name milk. You ask the shopkeeper and he tells you that there are different types of milk under different brands. You ask him to show you the milk of a particular brand and he shows you the milk of that brand. This is how namespaces work in C++.
Namespaces are used to organize code into logical groups and to prevent name collisions that can occur especially when your code base includes multiple libraries. The namespace provides a scope region (namespace scope) for identifiers (variables, functions, etc.). Identifiers declared inside a namespace are only accessible within that namespace.

Most common naming collisions are:

  • Two (or more) functions (or global variables) with the same name. This may be in the same library or in different libraries.

The std Namespace

When C++ was originally designed, all of the identifiers in the C++ standard library (including std::cin and std::cout) were available to be used without the std:: prefix (they were part of the global namespace). However, this meant that any identifier in the standard library could potentially conflict with any name you picked for your own identifiers (also defined in the global namespace). So C++ moved all of the functionality in the standard library into a namespace named “std” (short for standard).

:: Scope Resolution Operator

The :: symbol is called the scope resolution operator. It is used to access a variable, function, etc. in a namespace.

#include <iostream>

int main() {
    std::cout << "Hello World!";
    return 0;
}

Why to avoid using the using namespace directive

The using namespace directive is used to import all the identifiers from a namespace into the current scope. This defeats the purpose of namespaces. It is recommended to avoid using the using namespace directive.

#include <iostream>

using namespace std;  // not recommended

int main() {
    cout << "Hello World!";
    return 0;
}

Note
Always prefer using :: scope resolution operator over using namespace directive.

Preprocessor Directives

Preprocessor directives are special commands that are interpreted by the preprocessor before the actual compilation of the program begins. Preprocessor directives are not part of the C++ language.

They are used to perform tasks such as:

  • Including header files
  • Defining macros
  • Conditional compilation

#include Directive

The #include directive is used to include header files in the program. By including a header file, we can use the functions, classes, etc. defined in that header file.

#include <iostream>

#define Directive

The #define directive is used to define macros. Macros are used to define constants and to create simple functions.

Syntax

#define identifier replacement_text
#include <iostream>

#define PI 3.14159
#define AREA(r) (PI * r * r)
#define MY_RADIUS 2

int main() {
    std::cout << "Area of circle with radius " << MY_RADIUS << " is " << AREA(MY_RADIUS);
    return 0;
}

Conditional Compilation

Conditional compilation is used to include or exclude code from the program based on certain conditions.

#if Directive

The #if directive is used to check if a condition is true. If the condition is true, the code between #if and #endif is included in the program. If the condition is false, the code between #if and #endif is excluded from the program.

#include <iostream>

#define DEBUG

int main() {
    #if defined(DEBUG)
        std::cout << "Debug mode is on";
    #endif
    return 0;
}

Note
Fun Fact: You can use #if 0 to have same behaviour as commenting out a block of code.
Objects like macros don't affect other preprocessor directives.

#ifdef Directive

The #ifdef directive is used to check if a macro is defined. If the macro is defined, the code between #ifdef and #endif is included in the program. If the macro is not defined, the code between #ifdef and #endif is excluded from the program.

#include <iostream>

#define DEBUG

int main() {
    #ifdef DEBUG
        std::cout << "Debug mode is on";
    #endif
    return 0;
}

#ifndef Directive

The #ifndef directive is used to check if a macro is not defined. If the macro is not defined, the code between #ifndef and #endif is included in the program. If the macro is defined, the code between #ifndef and #endif is excluded from the program.

#include <iostream>

#define DEBUG

int main() {
    #ifndef DEBUG
        std::cout << "Debug mode is off";
    #endif
    return 0;
}

#else Directive

The #else directive is used to include a block of code if the condition in #if or #ifdef is false.

#include <iostream>

#define DEBUG

int main() {
    #if defined(DEBUG)
        std::cout << "Debug mode is on";
    #else
        std::cout << "Debug mode is off";
    #endif
    return 0;
}

#elif Directive

The #elif directive is used to check if a condition is true if the condition in #if or #ifdef is false.

#include <iostream>

#define DEBUG

int main() {
    #if defined(DEBUG)
        std::cout << "Debug mode is on";
    #elif defined(PRODUCTION)
        std::cout << "Production mode is on";
    #else
        std::cout << "Debug mode is off";
    #endif
    return 0;
}

#endif Directive

The #endif directive is used to mark the end of a conditional block.

#include <iostream>

#define DEBUG

int main() {
    #if defined(DEBUG)
        std::cout << "Debug mode is on";
    #elif defined(PRODUCTION)
        std::cout << "Production mode is on";
    #else
        std::cout << "Debug mode is off";
    #endif
    return 0;
}

Note
Preprocesser directives are valid from the point of their definition to the end of the file.
Defined directives in one code file do not affect other code files.

⏮️ Previous 🔝 Top Next ⏭️
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment