4.13 — Literals

In programming, a constant is a fixed value that may not be changed. C++ has two kinds of constants: literal constants, and symbolic constants. We’ll cover literal constants in this lesson, and symbolic constants in the next lesson.

Literal constants (usually just called literals) are values inserted directly into the code. For example:

They are constants because their values can not be changed dynamically (you have to change them, and then recompile for the change to take effect).

Just like objects have a type, all literals have a type. The type of a literal is assumed from the value and format of the literal itself.

By default:

Literal value Examples Default type
integral value 5, 0, -3 int
boolean value true, false bool
floating point value 3.4, -2.2 double (not float)!
char value ‘a’ char
C-style string “Hello, world!” const char[14]

Literal suffixes

If the default type of a literal is not as desired, you can change the type of a literal by adding a suffix:

Data Type Suffix Meaning
int u or U unsigned int
int l or L long
int ul, uL, Ul, UL, lu, lU, Lu, or LU unsigned long
int ll or LL long long
int ull, uLL, Ull, ULL, llu, llU, LLu, or LLU unsigned long long
double f or F float
double l or L long double

You generally won’t need to use suffixes for integer types, but here are examples:

By default, floating point literal constants have a type of double. To make them float literals instead, the f (or F) suffix should be used:

New programmers are often confused about why the following doesn’t work as expected:

Because 4.1 has no suffix, it’s treated as a double literal, not a float literal. When C++ defines the type of a literal, it does not care what you’re doing with the literal (e.g. in this case, using it to initialize a float variable). Therefore, the 4.1 must be converted from a double to a float before it can be assigned to variable f, and this could result in a loss of precision.

Literals are fine to use in C++ code so long as their meanings are clear. This is most often the case when used to initialize or assign a value to a variable, do math, or print some text to the screen.

String literals

In lesson 4.11 -- Chars, we defined a string as a collection of sequential characters. C++ supports string literals:

String literals are handled very strangely in C++ for historical reasons. For now, it’s fine to use string literals to print text with std::cout, but don’t try and assign them to variables or pass them to functions -- it either won’t work, or won’t work like you’d expect. We’ll talk more about C-style strings (and how to work around all of those odd issues) in future lessons.

Scientific notation for floating point literals

There are two different ways to declare floating-point literals:

In the second form, the number after the exponent can be negative:

Octal and hexadecimal literals

In everyday life, we count using decimal numbers, where each numerical digit can be 0, 1, 2, 3, 4, 5, 6, 7, 8, or 9. Decimal is also called “base 10”, because there are 10 possible digits (0 through 9). In this system, we count like this: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, … By default, numbers in C++ programs are assumed to be decimal.

In binary, there are only 2 digits: 0 and 1, so it is called “base 2”. In binary, we count like this: 0, 1, 10, 11, 100, 101, 110, 111, …

There are two other “bases” that are sometimes used in computing: octal, and hexadecimal.

Octal is base 8 -- that is, the only digits available are: 0, 1, 2, 3, 4, 5, 6, and 7. In Octal, we count like this: 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, … (note: no 8 and 9, so we skip from 7 to 10).

Decimal 0 1 2 3 4 5 6 7 8 9 10 11
Octal 0 1 2 3 4 5 6 7 10 11 12 13

To use an octal literal, prefix your literal with a 0:

This program prints:


Why 10 instead of 12? Because numbers are printed in decimal, and 12 octal = 10 decimal.

Octal is hardly ever used, and we recommend you avoid it.

Hexadecimal is base 16. In hexadecimal, we count like this: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, 12, …

Decimal 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Hexadecimal 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11

To use a hexadecimal literal, prefix your literal with 0x.

This program prints:


Because there are 16 different values for a hexadecimal digit, we can say that a single hexadecimal digit encompasses 4 bits. Consequently, a pair of hexadecimal digits can be used to exactly represent a full byte.

Consider a 32-bit integer with value 0011 1010 0111 1111 1001 1000 0010 0110. Because of the length and repetition of digits, that’s not easy to read. In hexadecimal, this same value would be: 3A7F 9826. This makes hexadecimal values useful as a concise way to represent a value in memory. For this reason, hexadecimal values are often used to represent memory addresses or raw values in memory.

Prior to C++14, there is no way to assign a binary literal. However, hexadecimal pairs provide us with a useful workaround:

C++14 binary literals and digit separators

In C++14, we can assign binary literals by using the 0b prefix:

Because long literals can be hard to read, C++14 also adds the ability to use a quotation mark (‘) as a digit separator.

If your compiler isn’t C++14 compatible, your compiler will complain if you try to use either of these.

Printing decimal, octal, hexadecimal, and binary numbers

By default, C++ prints values in decimal. However, you can tell it to print in other formats. Printing in decimal, octal, or hex is easy via use of std::dec, std::oct, and std::hex:

This prints:


Printing in binary is a little harder, as std::cout doesn’t come with this capability built-in. Fortunately, the C++ standard library includes a type called std::bitset that will do this for us (in the <bitset> header). To use std::bitset, we can define a std::bitset variable and tell std::bitset how many bits we want to store. The number of bits must be a compile time constant. std::bitset can be initialized with an unsigned integral value (in any format, including decimal, octal, hex, or binary).

This prints:

11000101 11000101

We can also create a temporary (anonymous) std::bitset to print a single value. In the above code, this line:

creates a temporary std::bitset object with 4 bits, initializes it with 0b1010, prints the value in binary, and then discards the temporary std::bitset.

Magic numbers, and why they are bad

Consider the following snippet:

A number such as the 30 in the snippet above is called a magic number. A magic number is a literal (usually a number) in the middle of the code that does not have any context. What does 30 mean? Although you can probably guess that in this case it’s the maximum number of students per class, it’s not absolutely clear. In more complex programs, it can be very difficult to infer what a hard-coded number represents, unless there’s a comment to explain it.

Using magic numbers is generally considered bad practice because, in addition to not providing context as to what they are being used for, they pose problems if the value needs to change. Let’s assume that the school buys new desks that allow them to raise the class size from 30 to 35, and our program needs to reflect that. Consider the following program:

To update our program to use the new classroom size, we’d have to update the constant 30 to 35. But what about the call to setMax()? Does that 30 have the same meaning as the other 30? If so, it should be updated. If not, it should be left alone, or we might break our program somewhere else. If you do a global search-and-replace, you might inadvertently update the argument of setMax() when it wasn’t supposed to change. So you have to look through all the code for every instance of the literal 30, and then determine whether it needs to change or not. That can be seriously time consuming (and error prone).

Although we say magic “numbers”, this affects all kinds of values. Consider this example

There’s only one number (100) in this example, but it’s also used in the strings. If we decide to update the maximum to let’s say 200, we have to update three different occasions of 100.

Fortunately, better options (symbolic constants) exist. We’ll talk about those in the next lesson.

Best practice

Don’t use magic numbers in your code.

4.14 -- Const, constexpr, and symbolic constants
4.12 -- An introduction to std::string

184 comments to 4.13 — Literals

  • Can someone explain for me what is the benefit of using octal and decimal(I dont see a good side of this section). And about the suffix i dont get it :).

  • Waldo Lemmer

    1. I'm not sure whether you want to get rid of all C++<=17 references on this website (0.12 says "Learncpp uses C++17. If your compiler isn’t capable of C++17, you won’t be able to follow all lessons"), but section "C++14 binary literals and digit separators" contains some.

    2. Will another programmer know what I'm talking about when I use the phrase "magic numbers"?

    • Alex

      1) I'm scrubbing out C++11 references, but keeping in C++14 and newer since some companies still haven't adopted C++17 or newer.

      2) Yes. It's a common enough phrase that it even has its own wikipedia:

  • Jay R

    This section number should be updated to 4.13 on this page.

  • Frido Kurniawan

    Hi, i'm completely new in programming (esp. c++) here and i just wonder what is the purpose of (assigning) binary literal in this programming language here? Thanks before.

    • Noman

      c++ often interacts with low level hardware where a bit can represent a hardware pin that you want to apply a voltage to, or similar ideas. Sometimes an 'integer' is really an 'array of bits' that indicate 'several switches being flipped' and its easier to read the code if you see it in binary instead of hex or decimal.  Before this addition I worked at a place that did embedded code and the programmers there had a header file that #defined Ob001001 type constants (the letter 'O' for 0) to support this.  It did not have every possible value but they added them as they needed them for each project and it had hundreds.  
      very little code requires bitset or binary numbers, but when it does, the language supports it.

  • Hali

    Hi, can you explain to me why 4.1 is a double literal and 5.0 is a floating type? I'm trying to understand between the two but i just wrap my head around it.

  • kiwikiz

    Sorry if I have a few questions but I'm very curious about how C++ work under the hood.
    Q1.Where are literals stored in memory?
    Q2.How does this 2 line of statement works?

    Correct me if I'm wrong, so above x is directly initialized with 0 and in line2, cpu fetches a copy of x and assign it to y?
    Q3. And also... this is turning into a bad habit of mine, where even for simple sentences above, I keep wondering how it works under the hood, you have any suggestion to like stop overthinking and keep it abstracted?

    • nascardriver

      Thinking under the hood is fine, but it's not possible to answer questions in a general manner. The answer depends on the compiler.
      I suggest you learn the basics of assembly, then you can see for yourself what's happening.

      Given the code

      With optimizations disabled (Optimizations would remove everything because the code doesn't do anything), clang generates

      rbp, rsp, eax, ecx are little variables that live on your CPU. They never get destroyed and are reused all of the time.
      [rbp - X] is a variable on the stack (memory).

      Line 4 answers Q1. Line 4 moves the value 0 into the stack variable [rbp - 4] (That's `x` from your code). The literal 0 is placed right inside the code. This is as fast as it's going to get.

      Line 5 and 6 answer Q2. [rbp - 4] (`x`) is moved into ecx. Then ecx is moved into [rbp - 8] (That's `y`). Moving from memory to memory isn't possible, that's why the value has to be moved into ecx first.
      For reference, if you also initialized `y` with 0, the code would be

      You can play with different compilers and optimization levels on compiler explorer

  • fritz

    "They are constants because their values can not be changed dynamically (you have to change them, and then recompile for the change to take effect)"

    Examples(it's given by you):

    (this thing isn't working because i edited it)

    what do you even mean by "You have to change them, and then recompile for the change to take effect", we cannot change the constants right? then what do you mean by changing? also what do you mean by changing dynamically?

    Thanks for your Website by the way.

    • nascardriver

      "changed dynamically" -> Changed after having been created
      "recompile for the change to take effect" -> If you want to print value other than "3.4", you have to change the value in code, then recompile the code. There's no way to change it without recompiling.

      • fritz

        so... You're talking about the Varibles right

        • nascardriver

          About the use of literals

          If you want this code to print anything other than "3.4", you have to change the value in code and recompile it. With a variable, the value could change at run-time. Not so with literals. Literals always have the same value.

  • Slyminc

    By default:
    literal value: integral value. you mean 'integer value'?

  • Martin


    should probably read

  • Shasha

    Hey, I am having a hard time understanding the implications of this line. Please elaborate...

    "Because there are 16 different values for a hexadecimal digit, we can say that a single hexadecimal digit encompasses 4 bits."

    • samivagyok

      Not the author, but I hope I can explain: the value of 1111 (binary, 4-bit) is 15. This is because 2^0 + 2^1 + 2^2 + 2^3 = 15. This is the biggest value we can take in binary with 4 bits. Hexadecimal uses 16 characters (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F), the biggest being F, with the value of 15. So basically, any 1 to 4 bit value, we can express with a single hexadecimal value.

  • Andreas Krug

    Hello Alex & nascardriver,

    in chapter 2.11 - Header files (The #include order of header files) you wrote to sort the headers alphabetically, but the second code example from (Printing decimal, octal, hexadecimal, and binary numbers) in this chapter has iostream before bitset.

    Keep up the great work,

  • Math

    When I run this code I get the following output:

    So what's the difference between all three ?
    I am really confused :(

    • nascardriver

      `std::cout` doesn't show you the full value, it cuts it off by default.

      before you start printing.
      `f1` and `f2` have the same value. You initialize `f2` with a `double`, but it gets converted to a `float`. This is allowed, because the value you're initializing it with is a literal. If you were to initialize it with a `double` variable, you'd get an error.

      • Math

        Thank you it worked!! And it makes much more sense now. Really appreciate the time and dedication you guys put in these lessons God bless you :)

  • Math

    Hello Alex and Nascardriver :)
    On the top of the page
    C-style string    “Hello, world!”    const char[14]
    Shouldn't it be const char[13]?

  • Just a little nitpick, shouldn't the warning right at the end of this guide be a Best practice instead?
    Loving the tutorials so far btw, many thanks for the dedication and effort which went into writing these!

  • sami

    I wish there were some ways to donate to your website! (other than clicking on Ads, which I keep doing that)
    I know donating is not enough and I know saying how thankful we are isn't enough. All I can do is to be like you; to be generous, to be helpful and to share knowledge with others.
    I am learning life lessons as well as C++ in this tutorial. Thank you so much. You have changed lots of life and mine too and I always as long as I remember wish you two a happy, long, wealthy, healthy, successful life. I LOVE you. I truly ENJOYED being here and learning. You two are extraordinary!

  • sami (std::oct)

    "std::cout << std::oct << x << '\n'; "
    "std::cout << std::setprecision(10) << 3.45 << '\n'; "

    Is "oct or setprecision(10) and etc." an object of class "std" in the same was as "std::cout"?
    I was wondering why C++ developers, didn't design "std::oct << x << '\n';" alone! Why do we have to use "std::oct" along with "std::cout"?
    Do you probably know the reason?

    • nascardriver

      `oct` and `setprecesion` are declared in the `std` namespace, just like `cout`.
      There are a bunch of modifiers for output streams, see
      They can be combined however you wish. Creating a separate object for each possible combination is impractical.
      Also note that modifiers are persistent. You don't have to use `std::oct` right before the number. Once it's set, it's set until you remove it.

  • Chayim

    —int maxStudents{ numClassrooms * 30 };
    Can you explain what this code step by step is and how it works?
      •—maxStudents— is a variable initialized to -int-, so what is —numClassrooms— it’s not an int value so how can it be in the value of -maxStudents- ?
      •What is * in the value?
      •Why is it called "magic"? What exactly is it different from a regular int code?

  • Chayim

    — std::cout << bin1 << ' ' << bin2 << '\n';—
    How does ' ' print a blank space if it does not have a backlash and t '/t' ?

  • Chayim

    What’s the difference between double and float?

    • bob jones

      a float has a min size of 4 bytes and is typically precise to 7 digits while a double has a min size of 8 bytes and is typically precise to 15 digits

  • Chayim

    -return 5; // 5 is an integer literal-
    What does return 5 literal mean in code and what does do? Because -return- returns a function to function main()

    • nascardriver

      `return` returns a value from a function. Please re-read lesson 2.2 to make sure you understood `return`.

      • Chayim

        I was unclear because in that lesson the example for return was a unknown value of a variable that had user input, so return 5 was unclear, because the example was return user input of variable, but now I guess that return 5 is when using return to simply return a declared value.

  • buku

    "They are constants because their values can not be changed dynamically (you have to change them, and then recompile for the change to take effect)"

    i think it is not correct , u can change value of plain variable , they called so "Literal constants" because u can't change the meaning of that literal
    just my opinion :)

Leave a Comment

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