Literals

What is a literal?

A literal is simply a value.

In the following line:

int var = 57;

The number 57 is a literal. More precisely, an integer literal.

In the line below:

float var2 = 49.12;

The number 49.12 is a floating point literal.

In the following line:

char c = 'L';

'L' is a character literal.

Here:

char str[] = "Some text.";

The string "Some text." is a string literal.

In the following line:

bool var3 = true;

true is a boolean literal.

Here is a table with the types of literal:

Type of literalExample
Integer432
Floating point57.376
character'd'
string"I am a string of character."
booleanfalse

Integer literals

Default types of integer literals

Let us define 3 overloads of a function that prints an integer number to the console:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream> void print(int num) { std::cout << "int: " << num << std::endl; } void print(long num) { std::cout << "long: " << num << std::endl; } void print(long long num) { std::cout << "long long: " << num << std::endl; }

If we call the function print, with the literal 100 as argument, like that:

print(100);

Which overload will be called? The one that takes an int as argument. Why? Integer literals are, by default, of the smallest type, between (int, unsigned, long, unsigned long, long long and unsigned long long), that can hold the value (Signed types are taken in priority). The smallest type, in the set, that can hold the number 100 is int.

Note that if, for example, the types unsigned and unsigned long are of the same size, the type of an integer literal may be unsigned long instead of unsigned.

It is possible to call the overload we want using explicit type castings:

1
2
3
4
5
6
7
8
int main() { print((int)23); print((long)99); print((long long)31); return 0; }

There is, however, a better way. It is possible to specify the type of literals using prefixes.

Specifying the type of integer literals

We specify the type of integer literals by adding, to them, the suffix that represents the type we want.

For example, in the line below, the overload void print(long num) is called:

print(200L);

Here is a table with the integer literal suffixes:

TypeSuffix
unsignedu
unsigned longul (Or lu)
unsigned long longull (Or llu)
longl
long longll

Note that suffixes are case insensitive. Therefore, ull or ULL are equivalent.

Here is a complete example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream> void print(int num) { std::cout << "int: " << num << std::endl; } void print(long num) { std::cout << "long: " << num << std::endl; } void print(long long num) { std::cout << "long long: " << num << std::endl; } void print(unsigned num) { std::cout << "unsigned: " << num << std::endl; } void print(unsigned long num) { std::cout << "unsigned long: " << num << std::endl; } void print(unsigned long long num) { std::cout << "unsigned long long: " << num << std::endl; } int main() { print(567); // int. print(567l); // long. print(567ll); // long long. print(567u); // unsigned. print(567ul); // unsigned long. print(567ull); // unsigned long long. print(4294967295); // unsigned long. print(9223372036854775807); // long long. print(18446744073709551615); // unsigned long long. return 0; }

Writing integer literals in hexadecimal

It is possible to write number literals in hexadecimal by prefixing them with 0x. The letters inside hexadecimal literals can be in either uppercase or lowercase.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream> int main() { std::cout << 0x1 << std::endl; std::cout << 0xa << std::endl; std::cout << 0xb << std::endl; std::cout << 0x10 << std::endl; std::cout << 0xa0 << std::endl; std::cout << 0xff << std::endl; std::cout << 0xFF << std::endl; std::cout << 0xFFFF << std::endl; std::cout << 0xffffffff << std::endl; return 0; }

We can also, using suffixes, specify the type of integer literals written in hexadecimal:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream> void print(int num) { std::cout << "int: " << num << std::endl; } void print(unsigned num) { std::cout << "unsigned: " << num << std::endl; } int main() { print(0xA); print(0xAu); print(0xau); return 0; }

Floating point literals

Default type of floating point literals

By default, floating point literals are always of double type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream> void print(float num) { std::cout << "float: " << num << std::endl; } void print(double num) { std::cout << "double: " << num << std::endl; } void print(double long num) { std::cout << "double long: " << num << std::endl; } int main() { print(23.48); print(565456.464646); print(937567753545350394.192574563569754); print(2048573657584836579847475857663.38346563839836362728576); return 0; }

As we can see, the last two numbers has been written using the scientific notation. The number before the e represents the digits and the number after it is the power of 10. For example, 1.23456e7 equals 12345600 (1.23456 * 107), 1.23456e0 equals 1.23456 (1.23456 * 100) and 1.23456e-3 equals 0.00123456 (1.23456 * 10-3).

Representing literals using the scientific notation

It is possible to use the scientific notation when defining floating point literals:

1
2
3
4
5
6
7
8
9
10
11
#include <iostream> int main() { std::cout << 1.564e2 << std::endl; // 156.4 std::cout << 5.743e-5 << std::endl; // 0.00005743 std::cout << 7.8e3 << std::endl; // 7800 std::cout << 1.234567E6 << std::endl; // 1234567 return 0; }

The e in the scientific notation is also case insensitive. So e or E both works.

Specifying the type of floating point literals

Like with integer literals, we use suffixes to specify the type of floating point literals.

Here is a table with the suffixes:

TypeSuffix
floatf
doubled
double longdl (Not ld)

Here is an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream> void print(float num) { std::cout << "float: " << num << std::endl; } void print(double num) { std::cout << "double: " << num << std::endl; } void print(double long num) { std::cout << "double long: " << num << std::endl; } int main() { print(123.456f); print(1.4F); print(1.2345e2f); // Scientific notation print(123.456d); print(47.87); double long var = 123456789.123456789dl; print(var); return 0; }

Note that, in order for a number to be considered a floating point literal, it must have a decimal point (Even if there is nothing after it). Otherwise, it is considered an integer literal. Therefore, if a number literal does not contain a decimal point, it can not be suffixed by f, d or dl.

Examples of faulty code lines:

float n = 56f; double n2 = 43d;

Examples of correct code lines:

float n = 56.f; double n2 = 56.0d;

The literal nullptr

The keyword nullptr is considered to be a literal. Its type is std::nullptr_t. We can define function overloads with arguments of that type, so they are called if the functions receive the literal nullptr as argument.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream> void func(void *ptr) { std::cout << "Pointer\n"; } void func(std::nullptr_t ptr) { std::cout << "nullptr\n"; } int main() { int *ptr = 0; int *ptr2 = nullptr; func(ptr); func(ptr2); func(nullptr); return 0; }