C/C++: sizeof(short), sizeof(int), sizeof(long), sizeof(long long), etc... on a 32-bit machine ve...

Learn c/c++: sizeof(short), sizeof(int), sizeof(long), sizeof(long long), etc... on a 32-bit machine versus on a 64-bit machine with practical examples, diagrams, and best practices. Covers c++, c,...

Understanding sizeof in C/C++: 32-bit vs. 64-bit Architectures

Hero image for C/C++: sizeof(short), sizeof(int), sizeof(long), sizeof(long long), etc... on a 32-bit machine ve...

Explore how the sizeof operator for fundamental data types like short, int, long, and long long can vary significantly between 32-bit and 64-bit systems in C and C++.

The sizeof operator in C and C++ is a fundamental tool for determining the memory footprint of data types and variables. While its behavior is often straightforward, understanding how it changes across different system architectures, particularly between 32-bit and 64-bit machines, is crucial for writing portable and efficient code. This article delves into the typical sizes of common integer types (short, int, long, long long) on these architectures and explains the underlying reasons for the variations.

The C/C++ Standard and Integer Sizes

The C and C++ standards do not specify exact sizes in bytes for integer types. Instead, they define minimum ranges and relationships between them. This flexibility allows compilers to optimize for the underlying hardware architecture. The key relationships are:

  • sizeof(char) is always 1 byte.
  • sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
  • short must be at least 16 bits.
  • int must be at least 16 bits.
  • long must be at least 32 bits.
  • long long must be at least 64 bits.

These minimums ensure that types can hold a certain range of values, but the actual sizes are implementation-defined, meaning they depend on the compiler and the target architecture.

flowchart TD
    A[C/C++ Standard] --> B{Minimum Size Requirements}
    B --> C[short: >= 16 bits]
    B --> D[int: >= 16 bits]
    B --> E[long: >= 32 bits]
    B --> F[long long: >= 64 bits]
    F --> G{Implementation Defined Actual Sizes}
    G --> H[32-bit Architecture]
    G --> I[64-bit Architecture]
    H --> J[Compiler Specific Sizes]
    I --> K[Compiler Specific Sizes]

How C/C++ Standard Defines Integer Type Sizes

Typical Sizes on 32-bit Architectures

On a 32-bit system, the CPU's registers and memory addresses are typically 32 bits wide. Compilers usually align data types to these widths for optimal performance. Here are the common sizes you'd expect:

  • char: 1 byte
  • short: 2 bytes
  • int: 4 bytes
  • long: 4 bytes
  • long long: 8 bytes

Notice that int and long are often both 4 bytes on 32-bit systems. This is a common convention, as 4 bytes (32 bits) is the native word size for such architectures, making operations on int and long equally efficient.

#include <iostream>

int main() {
    std::cout << "--- 32-bit System (Typical) ---\n";
    std::cout << "sizeof(char): " << sizeof(char) << " bytes\n";
    std::cout << "sizeof(short): " << sizeof(short) << " bytes\n";
    std::cout << "sizeof(int): " << sizeof(int) << " bytes\n";
    std::cout << "sizeof(long): " << sizeof(long) << " bytes\n";
    std::cout << "sizeof(long long): " << sizeof(long long) << " bytes\n";
    return 0;
}

C++ code to demonstrate sizeof on a typical 32-bit system.

Typical Sizes on 64-bit Architectures

On a 64-bit system, the CPU's registers and memory addresses are 64 bits wide. This often leads to long and pointer types expanding to 8 bytes to match the native word size, improving performance for memory addressing and larger integer operations. The common sizes are:

  • char: 1 byte
  • short: 2 bytes
  • int: 4 bytes
  • long: 8 bytes
  • long long: 8 bytes

Here, int typically remains 4 bytes, while long expands to 8 bytes. This distinction is important for portability, especially when dealing with system calls or data structures that rely on specific integer widths. The long long type remains 8 bytes, as it already met the 64-bit minimum requirement.

#include <iostream>

int main() {
    std::cout << "--- 64-bit System (Typical) ---\n";
    std::cout << "sizeof(char): " << sizeof(char) << " bytes\n";
    std::cout << "sizeof(short): " << sizeof(short) << " bytes\n";
    std::cout << "sizeof(int): " << sizeof(int) << " bytes\n";
    std::cout << "sizeof(long): " << sizeof(long) << " bytes\n";
    std::cout << "sizeof(long long): " << sizeof(long long) << " bytes\n";
    return 0;
}

C++ code to demonstrate sizeof on a typical 64-bit system.

Summary of Differences and Implications

The primary difference between 32-bit and 64-bit systems regarding sizeof for fundamental types lies in the long integer type. While int often remains 4 bytes on both, long typically expands from 4 bytes on 32-bit to 8 bytes on 64-bit systems. This change is significant for:

  • Memory Usage: Data structures containing many long variables will consume more memory on 64-bit systems.
  • Interoperability: When exchanging data between 32-bit and 64-bit applications (e.g., through files or network sockets), explicit sizing or serialization is necessary to prevent data corruption.
  • Pointer Sizes: On 64-bit systems, pointers (void*, int*, etc.) are also 8 bytes, reflecting the 64-bit address space. This impacts memory alignment and structure padding.

Understanding these differences is vital for debugging subtle issues related to data truncation, buffer overflows, and incorrect memory calculations when porting code or interacting with system-level APIs.

Hero image for C/C++: sizeof(short), sizeof(int), sizeof(long), sizeof(long long), etc... on a 32-bit machine ve...

Typical sizeof values for integer types across architectures.