Previous Page
Next Page

2.2. Integer Types

There are five signed integer types . Most of these types can be designated by several synonyms, which are listed in Table 2-1.

Table 2-1. Standard signed integer types

Type

Synonyms

signed char

 

int

signed, signed int

short

short int, signed short, signed short int

long

long int, signed long, signed long int

long long (C99)

long long int, signed long long, signed long long int


For each of the five signed integer types in Table 2-1, there is also a corresponding unsigned type that occupies the same amount of memory, with the same alignment: in other words, if the compiler aligns signed int objects on even-numbered byte addresses, then unsigned int objects are also aligned on even addresses. These unsigned types are listed in Table 2-2.

Table 2-2. Unsigned standard integer types

Type

Synonyms

_Bool

bool (defined in stdbool.h )

unsigned char

 

unsigned int

unsigned

unsigned short

unsigned short int

unsigned long

unsigned long int

unsigned long long

unsigned long long int


C99 introduced the unsigned integer type _Bool to represent Boolean truth values. The Boolean value true is coded as 1, and false is coded as 0. If you include the header file stdbool.h in a program, you can also use the identifiers bool, TRue, and false, which are familiar to C++ programmers. The macro bool is a synonym for the type _Bool, and true and false are symbolic constants equal to 1 and 0.

The type char is also one of the standard integer types. However, the one-word type name char is synonymous either with signed char or with unsigned char, depending on the compiler. Because this choice is left up to the implementation, char, signed char, and unsigned char are formally three different types.

If your program relies on char being able to hold values less than zero or greater than 127, you should be using either signed char or unsigned char instead.


You can do arithmetic with character variables. It's up to you to decide whether your program interprets the number in a char variable as a character code or as something else. For example, the following short program treats the char value in ch as both an integer and a character, but at different times:

    char ch = 'A';               // A variable with type char.
    printf("The character %c has the character code %d.\n", ch, ch);
    for ( ; ch <= 'Z'; ++ch )
      printf("%2c", ch);

In the printf( ) statement, ch is first treated as a character that gets displayed, and then as numeric code value of the character. Likewise, the for loop treats ch as an integer in the instruction ++ch, and as a character in the printf( ) function call. On systems that use the 7-bit ASCII code, or an extension of it, the code produces the following output:

    The character A has the character code 65.
     A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

A value of type char always occupies one bytein other words, sizeof(char) always yields 1and a byte is at least eight bits wide. Every character in the basic character set can be represented in a char object as a positive value.

C defines only the minimum storage sizes of the other standard types: the size of type short is at least two bytes, long at least four bytes, and long long at least eight bytes. Furthermore, although the integer types may be larger than their minimum sizes, the sizes implemented must be in the order:

sizeof(short) sizeof(int) sizeof(long) sizeof(long long)

The type int is the integer type best adapted to the target system's architecture, with the size and bit format of a CPU register.

The internal representation of integer types is binary. Signed types may be represented in binary as sign and magnitude, as a one's complement , or as a two's complement . The most common representation is the two's complement. The non-negative values of a signed type are within the value range of the corresponding unsigned type, and the binary representation of a non-negative value is the same in both the signed and unsigned types. Table 2-3 shows the different interpretations of bit patterns as signed and unsigned integer types.

Table 2-3. Binary representations of signed and unsigned 16-bit integers

Binary

Decimal value as unsigned int

Decimal value as signed int, one's complement

Decimal value as signed int, two's complement

00000000 00000000

0

0

0

00000000 00000001

1

1

1

00000000 00000010

2

2

2

...

   

01111111 11111111

32,767

32,767

32,767

10000000 00000000

32,768

-32,767

-32,768

10000000 00000001

32,769

-32,766

-32,767

...

   

11111111 11111110

65,534

-1

-2

11111111 11111111

65,535

-0

-1


Table 2-4 lists the sizes and value ranges of the standard integer types.

Table 2-4. Common storage sizes and value ranges of standard integer types

Type

Storage size

Minimum value

Maximum value

char

(same as either signed char or unsigned char)

unsigned char

one byte

0

255

signed char

one byte

-128

127

int

two bytes or four bytes

-32,768 or -2,147,483,648

32,767 or 2,147,483,647

unsigned int

two bytes or four bytes

0

65,535 or 2,147,483,647

short

two bytes

-32,768

32,767

unsigned short

two bytes

0

65,535

long

four bytes

-2,147,483,648

2,147,483,647

unsigned long

four bytes

0

4,294,967,295

long long(C99)

eight bytes

-9,223,372,036, 854,775,808

9,223,372,036, 854,775,807

unsigned long long (C99)

eight bytes

0

18,446,744,073, 709,551,615


In the following example, each of the int variables iIndex and iLimit occupies four bytes on a 32-bit computer:

    int iIndex,            // Define two int variables and
        iLimit = 1000;     // initialize the second one.

To obtain the exact size of a type or a variable, use the sizeof operator. The expressions sizeof(type) and sizeof expression yield the storage size of the object or type in bytes. If the operand is an expression, the size is that of the expression's type. In the previous example, the value of sizeof(int) would be the same as sizeof(iIndex): namely, 4. The parentheses around the expression iIndex can be omitted.

You can find the value ranges of the integer types for your C compiler in the header file limits.h , which defines macros such as INT_MIN, INT_MAX, UINT_MAX, and so on (see Chapter 15). The program in Example 2-1 uses these macros to display the minimum and maximum values for the types char and int.

Example 2-1. Value ranges of the types char and int
// limits.c: Display the value ranges of char and int.
// ---------------------------------------------------
#include <stdio.h>
#include <limits.h>     // Contains the macros CHAR_MIN, INT_MIN, etc.

int main( )
{
  printf("Storage sizes and value ranges of the types char and int\n\n");
  printf("The type char is %s.\n\n", CHAR_MIN < 0 ? "signed" :"unsigned");

  printf(" Type   Size (in bytes)   Minimum         Maximum\n"
         "---------------------------------------------------\n");
  printf(" char %8d %20d %15d\n", sizeof(char), CHAR_MIN, CHAR_MAX );
  printf(" int  %8d %20d %15d\n", sizeof(int), INT_MIN, INT_MAX );
  return 0;
}

In arithmetic operations with integers , overflows can occur. An overflow happens when the result of an operation is no longer within the range of values that the type being used can represent. In arithmetic with unsigned integer types, overflows are ignored. In mathematical terms, that means that the effective result of an unsigned integer operation is equal to the remainder of a division by UTYPE_MAX + 1, where UTYPE_MAX is the unsigned type's maximum representable value. For example, the following addition causes the variable to overflow:

    unsigned int ui = UINT_MAX;
    ui += 2;                       // Result: 1

C specifies this behavior only for the unsigned integer types. For all other types, the result of an overflow is undefined. For example, the overflow may be ignored, or it may raise a signal that aborts the program if it is not caught.

2.2.1. Integer Types with Exact Width (C99)

The width of an integer type is defined as the number of bits used to represent a value, including the sign bit. Typical widths are 8, 16, 32, and 64 bits. For example, the type int is at least 16 bits wide.

In C99, the header file stdint.h defines integer types to fulfill the need for known widths. These types are listed in Table 2-5. Those types whose names begin with u are unsigned. C99 implementations are not required to provide the types marked as "optional" in the table.

Table 2-5. Integer types with defined width

Type

Meaning

Implementation

intN_t

uintN_t

An integer type whose width is exactly N bits

Optional

int_leastN_t

uint_leastN_t

An integer type whose width is at least N bits

Required for N = 8, 16, 32, 64

int_fastN_t

uint_fastN_t

The fastest type to process whose width is at least N bits

Required for N = 8, 16, 32, 64

intmax_t

uintmax_t

The widest integer type implemented

Required

intptr_t

uintptr_t

An integer type wide enough to store the value of a pointer

Optional


For example, int_least64_t and uint_least64_t are integer types with a width of at least 64 bits. If an optional signed type (without the prefix u) is defined, then the corresponding unsigned type (with the initial u) is required, and vice versa. The following example defines and initializes an array whose elements have the type int_fast32_t:

    #define ARR_SIZE 100
    int_fast32_t arr[ARR_SIZE];       // Define an array arr
                                      // with elements of type int_fast32_t 

      for ( int i = 0; i < ARR_SIZE; ++i )
        arr[i] = (int_fast32_t)i;     // Initialize each element

The types listed in Table 2-4 are usually defined as synonyms for existing standard types. For example, the stdint.h file supplied with one C compiler contains the line:

    typedef signed char    int_fast8_t;

This declaration simply defines the new type int_fast8_t (the fastest 8-bit signed integer type) as being equivalent with signed char.

Furthermore, an implementation may also define extended integer types such as int24_t or uint_least128_t.

The signed intN_t types have a special feature: they must use the two's complement binary representation. As a result, their minimum value is -2N-1, and their maximum value is 2N-1 - 1.

The value ranges of the types defined in stdint.h are also easy to obtain: macros for the greatest and least representable values are defined in the same header file. The names of the macros are the uppercased type names, with the suffix _t (for type) replaced by _MAX or _MIN (see Chapter 15). For example, the following definition initializes the variable i64 with its smallest possible value:

    int_least64_t i64 = INT_LEAST64_MIN;

The header file inttypes.h includes the header file stdint.h, and provides other features such as extended integer type specifiers for use in printf( ) and scanf( ) function calls (see Chapter 15).


Previous Page
Next Page