2.8 — Literals

C++ has two kinds of constants: literal, and symbolic. In this lesson, we’ll cover literals.

Literal constants

Literal constants (usually just called “literals”) are values inserted directly into the code. They are constants because you can’t change their values. For example:

While boolean and integer literals are pretty straightforward, there are two different ways to declare floating-point literals:

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

Numeric literals can have suffixes that determine their types. These suffixes are optional, as the compiler can usually tell from context what kind of constant you’re intending.

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 probably 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 convert them into a float value, the f or F suffix can be used:

C++ also supports char and string literals:

Char literals work just like you’d expect. However, string literals are handled very strangely in C++. 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.

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

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 provides us with an 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.

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 hard-coded 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).

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

Rule: Don’t use magic numbers in your code.

2.9 -- Const, constexpr, and symbolic constants
2.7 -- Chars

73 comments to 2.8 — Literals

  • Matthew


    Will I have to worry about the suffixes? As you said, the compiler should be able to tell what type I am using based on what type the variable is.

    • nascardriver

      Hi Metthew!
      For floats, yes please, because without the 'f' the number will be treated as a double, not a float. Otherwise, you rarely see them, they're sometimes used for (unsigned) long long, but that's about it.

    • Alex

      Yes, you do have to worry about suffixes, and no the compiler won't infer the literal's type from the variable being initialized with the literal.

  • Sndn

    Hi Alex,

    I want to check out the C++ 14 functionality in this tutorial, in eclipse. How do I do that? I'm using MinGW-w64.

    • Alex

      I'm not sure. See if your version of MinGW-w64 has a flag to enable c++14 functionality (something like -std=c++14) and if so, see if you can add that flag to your compiler settings so it gets passed whenever your compiler is called from eclipse.

  • Jason R.

    I'm not sure if you know or not or if it even fits within the scope of this particular lesson but I learned this trick (from a computer networking book) for converting from hexadecimal to binary and vice versa.  The only prerequisite is knowing the hexadecimal-binary equivalents for each hexadecimal digit.  

    Since each digit in hexadecimal is 4 bits of information you can break down a large hexadecimal number one digit at a time and create 4-bit groups independent of each other.  It fits in nicely with the programmer's mantra of breaking one large problem into more smaller problems.  

    As an example:  AFED can be broken down one digit at a time.  Since A = 1010, F = 1111, E = 1110, and D = 1101, then that means that AFED is equivalent to 1010 1111 1110 1101.

  • Muharrem

    Dear Alex, first of all thank you very much for this great tutorial.
    I have a question about the hexadecimal example that I quoted below.

    I thought "int bin(0)" will initialize a 2 byte integer (or 4 byte integer on modern architectures) as explained in chapter 2.4. But the assigned binary is 1 byte. Does C++ truncate the integer to 1 byte if the assigned literal can fit into 1 byte? Or any other reason?

    • Alex

      > Does C++ truncate the integer to 1 byte if the assigned literal can fit into 1 byte? Or any other reason?

      bin = 0x01 is the equivalent of bin = 1. In either case C++ will simply assign the value of 1 to the integer, regardless of the integer's size.

Leave a Comment

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