Tip of the Week #175: Changes to Literal Constants in C++14 and C++17.

Originally posted as TotW #175 on January 30, 2020

By James Dennett

Updated 2020-04-06

Quicklink: abseil.io/tips/175

“The only thing that stays the same is change” – Melissa Etheridge

Overview

C++ now has some features that can make numeric literals more readable.

Integer literals can now be written in binary (0b00101010) as well as the decimal (42), hex (0x2A), and octal (052) formats that have been supported since the dawn of time.

Single quotes (') serve as digit separators, and can be used to group digits in numeric literals of any base (0xDEAD'C0DE).

Floating point literals can be specified in hex (0x2A0p-4).

Binary Literals

Binary literals such as 0b1110'0000 can be more readable than hex (the next best option) when manipulating bit sets or working with low-level protocols.

Digit Separators

C++14 allows a single quote (') to be used to group digits in a numeric literal. These digit separators have no effect on the value of the constant: their only function is to help readers. They can make it easy to see at a glance how many digits are present, and know that none are missing. For example, 1'000'000'000 is more obviously one billion than is 1000000000 (and unlike 1e9 it is an integer, not a floating point value).

There are no restrictions on the number of digits per group, not even a requirement of consistency within a literal: 0b1'001'0001 is a valid way to write the number 145 (and may even make sense for a byte that is interpreted as three separate fields).

Hex Floating Point Literals

While most decimal floating point literals are not exactly representable in the binary floating point formats used by most computers, hex floating literals do map directly to bit patterns in floating point so long as enough bits are available. This avoids rounding errors when converting a literal to floating point format (though truncation errors are still possible if too many hex digits are present).

Hex floating point literals are indicated by writing a p (or P) to separate the significand from the exponent—where decimal floating point literals would use e (or E). For example, 0x2Ap12 is another way to write the value 0x2A << 12, i.e., 0x2A000, except that is a floating point value, not an integer. As a result, our style guide requires it to be written as 0x2A.0p12 to be explicit that it is a floating point value and not just another way to write an integer.

The exponent is always written in decimal, denotes a power of 2, and may be negative: 0x1p-10 is (exactly) 1.0/1024.

Recommendations

  • Binary literals should be used sparingly, for code which cares about bit manipulation.
  • Consider using digit separators when a numeric literal is too long to take in at a single glance.
  • When using digit separators, use conventional group sizes:
    • For decimal, use groups of three digits unless there is a conflicting convention (as with some currencies, for example).
    • For binary, prefer groups of four bits (nibble) or eight bits (octet/byte) unless the digits have a more semantically significant grouping.
    • For hex, use groups of 2, 4 or 8 hex digits.

See Also


Subscribe to the Abseil Blog