Literals and const
Suppose you’re writing a small program and you use 0.08 as the tax rate in ten different places. Three months later, the tax rate changes. Now you have to hunt down every 0.08 and hope you don’t miss one.
This is the problem that constants solve.
Before we get to constants though, let’s understand what a literal is.
What is a literal?
A literal is a value you write directly into source code. You’ve already seen these:
int score = 100;double tax_rate = 0.08;char grade = 'A';bool is_valid = true;Each of those values on the right (100, 0.08, 'A', true) is a literal. It’s a fixed value baked directly into your program text.
The type of a literal
Literals have types, just like variables do. C++ figures out the type from how you write the value. For example:
100is anint100.0is adouble100.0fis afloat(thefsuffix makes this explicit)'A'is achar"hello"is a string literal (we’ll cover its type properly in Chapter 7)trueandfalsearebool
The f suffix tells C++ to treat the value as a float rather than a double. If you omit the suffix, C++ will create a double literal and then convert it to a float. This may result in a value being squeezed into a type that can’t represent it as precisely.
There are also integer suffixes:
long population = 8000000000L; // 'L' forces longunsigned int flags = 255U; // 'U' forces unsignedlong long big = 9000000000000LL; // 'LL' forces long longOther bases
You can write integer literals in other bases too. Note that each prefix below starts with a zero (0), not the letter O:
int hex_color = 0xFF5733; // hexadecimal (starts with 0x)int permissions = 0755; // octal (starts with 0)int bits = 0b10110011; // binary (starts with 0b, C++14 and later)The decimal system we use every day has ten digits: 0-9. Hexadecimal has sixteen, so after 9 it continues with A-F. Octal uses 0-7. Binary uses only 0 and 1. You’ll encounter hex most often when working with colors or low-level bit patterns.
Digit separators
C++14 also lets you use single quotes as digit separators for readability:
long distance_km = 384'400;int big_number = 1'000'000;This makes large numbers much easier to read at a glance. The separators are purely cosmetic and the compiler completely ignores them.
The const keyword
Back to the tax rate problem. Instead of scattering a raw value like 0.08 across your code, you declare a variable once to hold it and mark it as unchangeable. This can be done using the const keyword:
The const keyword tells the compiler: this variable’s value may not change after initialization. If you modify the above code by uncommenting line 5, you’ll get a compile error. This is one of C++’s core philosophies: catch errors as early as possible.
The naming convention ALL_CAPS for constants is just a convention. C++ doesn’t enforce it. But it’s nearly universal in C++ code, and following it signals intent immediately. When a reader sees TAX_RATE, they know at a glance it’s not going to change.
Initializing a const variable
Unlike a regular variable, a const variable has to be given a value when it’s declared. This makes sense because if you can’t modify it later, where else would you set it?
const double TAX_RATE; // compile error: uninitialized constUsing const with other types
const works with any type:
const int MAX_RETRIES = 3;const char NEWLINE = '\n';const bool DEBUG_MODE = false;Key takeaways
- A literal is a value written directly in source code. Its type depends on how you write it.
constmarks a variable as unchangeable after initialization. Trying to modify it is a compile error.- The naming convention
ALL_CAPSfor constants is near-universal in C++.