Integer Widths in C++: long
, long long
, and Beyond
C++ provides a range of integer types, and understanding their differences, particularly the use of long
and long long
, can be crucial for writing efficient and portable code. This tutorial explains these types, their origins, and how they differ across various platforms.
The Basics: int
, short
, and long
At the foundation, C++ has integer types like int
, short
, and long
. These represent whole numbers, but they vary in the amount of memory they occupy, which dictates the range of values they can hold. The int
type is often the ‘natural’ size for the target architecture (e.g., 32 or 64 bits). short
is typically smaller than int
, and long
is typically at least as large as int
.
Historically, the long
type was introduced to provide a wider integer representation than the standard int
. However, the exact size of these types isn’t fixed by the C++ standard itself; it depends on the compiler and the underlying hardware architecture.
Introducing long long
The long long
type was added to the C++ standard (C++99 and later) to guarantee a wider integer representation, at least 64 bits wide. This provides a means to store very large integer values that wouldn’t fit within a standard long
on some systems.
long
vs. long int
and long long
vs. long long int
It’s important to understand that long
is simply a shorthand for long int
, and long long
is a shorthand for long long int
. The int
suffix is optional and doesn’t change the type. Both forms are valid and equivalent.
Guaranteed Sizes and Portability
The C++ standard guarantees minimum sizes for integer types, but the actual size can vary depending on the platform. Here’s a breakdown of the minimum guaranteed ranges:
char
: At least 8 bitsshort
: At least 16 bitsint
: At least 16 bitslong
: At least 32 bitslong long
: At least 64 bits
This means a long long
will always be at least 64 bits, but a long
might be 32 or 64 bits depending on the system.
Data Models and Platform Differences
The variations in long
‘s size arise from different 64-bit data models. These models determine the size of pointers and long integers on 64-bit architectures:
- LP64: (Used on Linux and macOS)
long
is 64 bits,int
is 32 bits. Pointers are 64 bits. - LLP64: (Used on Windows)
long
is 32 bits,long long
is 64 bits. Pointers are 64 bits.
This means that a program that assumes a fixed size for long
might behave differently on Linux and Windows.
Best Practices and Modern C++
To avoid ambiguity and ensure portability, modern C++ encourages using fixed-width integer types provided by the <cstdint>
header. These types offer precise control over integer sizes:
#include <cstdint>
int main() {
std::int8_t small_value; // Exactly 8 bits
std::int16_t short_value; // Exactly 16 bits
std::int32_t int_value; // Exactly 32 bits
std::int64_t long_value; // Exactly 64 bits
std::size_t index; // Unsigned integer type suitable for array indexing
return 0;
}
These types eliminate the platform-dependent behavior of int
, long
, and long long
, leading to more predictable and portable code. std::size_t
is particularly useful for representing sizes and indices, as it’s guaranteed to be large enough to hold the size of any object.
long double
Finally, long double
is a floating-point type that provides extended precision compared to double
. While not an integer type, it’s often used alongside integers for calculations and is guaranteed to have at least as much precision as double
. The exact precision of long double
is platform-dependent.