Skip to content
Laviyx Learn

Try

C++ course menu

C++ Constants: const, constexpr, Literals and Avoiding Magic Numbers

Learn to make values that cannot change in C++: const variables, constexpr compile-time constants, constexpr functions, literal suffixes and digit separators, and why named constants beat magic numbers and #define.

Beginner7 min readUpdated
On this page

Some values should never change while a program runs: the number of days in a week, a tax rate, the size of a game board. Marking them as constants documents that intent, and the compiler stops anyone (including you) from changing them by accident.

const: a value that cannot change#

Put const before the type. A constant must be initialized when it is created:

C++
#include <iostream>

int main() {
    const double gst_rate = 0.18;
    const int days_per_week = 7;

    double price = 1000;
    std::cout << "Tax: " << price * gst_rate << '\n';
    std::cout << "Hours in a week: " << days_per_week * 24 << '\n';
}
Output
Tax: 180
Hours in a week: 168

Trying to change a constant is a compile error:

C++
int main() {
    const int max_users = 100;
    max_users = 200;   // error: assignment of read-only variable
}

A const value can come from a calculation done while the program runs, such as user input. It just cannot change afterwards.

constexpr: known at compile time#

constexpr goes one step further: the value must be computable while compiling. That lets the compiler use it anywhere a fixed number is required, such as the size of an array, and it costs nothing at run time:

C++
#include <array>
#include <iostream>

int main() {
    constexpr int board_size = 8;
    constexpr int squares = board_size * board_size;

    std::array<int, squares> board{};
    std::cout << "Squares: " << board.size() << '\n';
}
Output
Squares: 64

A rule of thumb: use constexpr for fixed values written in your code, and const for values that are calculated at run time but should not change afterwards.

constexpr functions#

A function marked constexpr can be evaluated by the compiler when its arguments are constants, and still be called normally with run-time values:

C++
#include <iostream>

constexpr int square(int n) {
    return n * n;
}

int main() {
    constexpr int area = square(12);   // calculated while compiling
    int side = 5;
    std::cout << area << ' ' << square(side) << '\n';
}
Output
144 25

Avoid magic numbers#

A magic number is an unexplained value in the middle of code. Compare:

C++
// What is 0.18? What is 3?
double total = price * 1.18;
if (attempts > 3) { /* ... */ }
C++
constexpr double gst_rate = 0.18;
constexpr int max_login_attempts = 3;

double total = price * (1 + gst_rate);
if (attempts > max_login_attempts) { /* ... */ }

The second version explains itself, and if the rate changes you update one line.

Why not #define?#

Older code defines constants with the preprocessor:

C++
#define MAX_USERS 100

#define is plain text replacement done before compiling: it has no type and ignores scope, so the name can clash with anything. Prefer constexpr int max_users = 100;, which has a type, follows normal scope rules and shows up in the debugger.

Literals, suffixes and digit separators#

A value written directly in code is a literal. Its form decides its type:

LiteralType
42int
42LLlong long
42uunsigned int
3.14double
3.14ffloat
'x'char
0xFFint written in hexadecimal (255)
0b1010int written in binary (10)

Since C++14, an apostrophe can separate digits to make long numbers readable. It does not change the value:

C++
#include <iostream>

int main() {
    long long population = 1'428'627'663;
    int mask = 0b1111'0000;
    std::cout << population << ' ' << mask << ' ' << 0xFF << '\n';
}
Output
1428627663 240 255

Common mistakes#

Practice#

Practice exercise

A cinema has 12 rows of 18 seats. Store both numbers as constexpr constants, calculate the total number of seats as another constexpr, and print how many seats remain if 150 tickets have been sold.

Show solution
C++
#include <iostream>

int main() {
    constexpr int rows = 12;
    constexpr int seats_per_row = 18;
    constexpr int total_seats = rows * seats_per_row;

    int sold = 150;
    std::cout << "Total: " << total_seats << '\n';
    std::cout << "Remaining: " << total_seats - sold << '\n';
}
Output
Total: 216
Remaining: 66

sold is an ordinary variable because the number of tickets sold changes while the cinema is open.

Key takeaway#

Finished this lesson?