Integer Types

C includes several integer types each with a successively larger range of values. For each signed integer type, there is corresponding (but different) unsigned integer type.

The rules for these types are somewhat complex to account for the wide variety of systems where C is implemented, but can be summarized as follows,

Representation

Every integer type is consists value, padding, and sign bits.

Value bit

Value bits are assigned successive powers of 2 (i.e. 2^0, 2^1, 2^2, ...) and contribute to the integer’s value. The order of value bits is unspecified (intended to account for endianness).

The number of value bits in an integer is called its precision.

Padding bit

Padding bits do not contribute to the value of an integer. Two integers may compare equal even when their padding bits differ.

Sign bit

A bit which indicates that a signed integer is positive, when unset, or negative, when set. Signed integers have one signed bit, while unsigned integers do not have a signed bit.

Signed integers must be represented using one of the following implementations, where N is its precision:

Implementation

Sign Bit Value

Minimum Value

Maximum Value

Sign and Magnitude

Negates Value Bits

-2^N + 1

2^N - 1

One’s Complement

-2^N - 1

-2^N + 1

2^N - 1

Two’s Complement

-2^N

-2^N

2^N - 1

Positive signed values are required to have the exact same representation as the same value in the corresponding unsigned type. An integer’s width is the number of sign and value bits, which is always equal to or one more than its precision, for unsigned and signed integers, respectively.

Minimum Range and Size

Every integer type has a defined minimum range of values, which implies a minimum width. These values correspond to familiar AMD64 register sizes:

Type

Corresponding Register

Width

Signed Range

Unsigned Max

char

al and ah

8

\pm 2^{7} - 1

2^{8} - 1

short

ax

16

\pm 2^{15} - 1

2^{16} - 1

long

eax

32

\pm 2^{31} - 1

2^{32} - 1

long long

rax

64

\pm 2^{63} - 1

2^{64} - 1

The actual implemented size of each type depends on the chosen data model, which defines the size of each of these types along with the size of a pointer (memory address) of a particular system. The two most common x86-64 data models are LLP64 (Windows) and LP64 (Unix) are almost equivalent, differing only in the size of long:

Environment

Data Model

short

int

long

long long

Pointer Size

Windows

LLP64

16

32

32

64

64

Unix

LP64

16

32

64

64

64

The exact range that each type supports on a particular system is exposed through various macros defined in the limits.h header.

Integer Rank

The precision of each type can be greater than the minimum specified, but the following ranking of precision must be observed so that each type can represent any value of a type that it outranks:

signed charshortintlonglong long