uintptr_t in stdint

What is uintptr_t?

uintptr_t is an unsigned integer type defined in the <stdint.h> header of the C standard library. It is designed to be large enough to hold any pointer value. This makes it an essential type for scenarios where pointers need to be manipulated as integers.

This type is guaranteed to be large enough to hold any pointer value, making it an essential tool for portable and platform-independent pointer manipulation.

History

C99 Standard:

  • The C99 standard, published in 1999, introduced stdint.h, which defines fixed-width integer types.
  • Within stdint.h, the types uintptr_t and intptr_t were introduced. uintptr is an unsigned integer type capable of holding any integer value.

Why use uintptr_t?

 1 Portability:

  • Different architectures (e.g., 32-bit vs. 64-bit) have different pointer sizes. Using uintptr_t ensures that your code can handle pointers correctly regardless of the underlying architecture.

Its Size

The size of uintptr_t varies depending on the architecture of the system because it is designed to be able to hold any pointer value.

32-bit Architectures:

  1.  32-bit x86 (IA-32)
    1. Size of uintptr_t: 4 bytes (32 bits)
    2. Pointers on 32-bit x86 architectures are 32 bits, so uintptr_t is also 32 bits to accommodate this.
  2. ARM (32-bit)
    1. Size of uintptr_t: 4 bytes (32 bits)
    2. Similar to x86, pointers are 32 bits in a 32-bit ARM architecture.

64-bit Architectures:

  1. 64-bit x86 (x86_64 or AMD64)
    1. Size of uintptr_t: 8 bytes (64 bits)
    2. Pointers on 64-bit x86 architectures are 64 bits, so uintptr_t is also 64 bits to accommodate this.
  2. ARM (64-bit, ARM64 or AArch64)
    1. Size of uintptr_t: 8 bytes (64 bits)
    2. Similar to x86_64, pointers are 64 bits in a 64-bit ARM architecture.

Other Architectures:

  1. 64-bit PowerPC (PPC64)
    1. Size of uintptr_t: 8 bytes (64 bits)
    2. Pointers in 64-bit PowerPC architectures are 64 bits, so uintptr_t follows suit.
  2. 64-bit SPARC (SPARC64)
    1. Size of uintptr_t: 8 bytes (64 bits)
    2. Pointers in 64-bit SPARC architectures are also 64 bits.

Summary Table

ArchitectureSize of uintptr_t
32-bit x86       4 bytes (32 bits)
32-bit ARM      4 bytes (32 bits)
64-bit x86_64  8 bytes (64 bits)
64-bit ARM64  8 bytes (64 bits)
64-bit PPC64   8 bytes (64 bits)
64-bit SPARC648 bytes (64 bits)

Explanation:

  • The size of uintptr_t is directly related to the size of pointers on the given architecture.
  • On 32-bit architectures, pointers are 32 bits long, making uintptr_t 32 bits.
  • On 64-bit architectures, pointers are 64 bits long, making uintptr_t 64 bits.

Implementation

#define NULL ((void *)0UL)

typedef unsigned long uintptr_t;
typedef long size_t;

Explanation:

  • uintptr_t is defined as unsigned long.
  • size_t is defined as long.

Size Determination by Architecture:

The size of unsigned long and long can vary depending on the architecture and the platform-specific implementation.

32-bit Architectures:

  • On most 32-bit systems (e.g., 32-bit x86):
    • unsigned long: 4 bytes (32 bits)
    • long: 4 bytes (32 bits)

Thus, on a 32-bit architecture:

  • uintptr_t (defined as unsigned long) will be 4 bytes.
  • size_t (defined as long) will be 4 bytes.

64-bit Architectures:

  • On most 64-bit systems (e.g., 64-bit x86_64, 64-bit ARM):
    • unsigned long: 8 bytes (64 bits)
    • long: 8 bytes (64 bits)

Thus, on a 64-bit architecture:

  • uintptr_t (defined as unsigned long) will be 8 bytes.
  • size_t (defined as long) will be 8 bytes.

Summary Table

ArchitectureSize of uintptr_tSize of size_t
 32-bit                    4 bytes (32 bits)4 bytes (32 bits)
64-bit                     8 bytes (64 bits)8 bytes (64 bits)

Why cant we use unsigned int for uintptr_t and size_t:

Because:

32-bit Systems

  • On most 32-bit systems:
    • int is typically 4 bytes (32 bits).
    • long is typically 4 bytes (32 bits).

In this case, both unsigned int and unsigned long would be 4 bytes, so theoretically, using unsigned int for uintptr_t and size_t would work fine.

64-bit Systems

  • On most 64-bit systems:
    • int is typically still 4 bytes (32 bits).
    • long is typically 8 bytes (64 bits).

In this case, unsigned int would be 4 bytes, while unsigned long would be 8 bytes. Since pointers on 64-bit systems are 64 bits, unsigned int would not be able to hold a pointer value correctly. Thus, using unsigned int for uintptr_t and size_t would fail to represent pointer values on 64-bit architectures.

Why unsigned long is Used:

  • unsigned long is chosen because it typically matches the size of pointers on most architectures:
    • 32-bit systems: unsigned long is 4 bytes, matching 32-bit pointers.
    • 64-bit systems: unsigned long is 8 bytes, matching 64-bit pointers.

This ensures that uintptr_t can hold any pointer value, making it safe and portable across different architectures.