1.3 Basic Types

The type of a variable determines how much space it occupies in storage and how the bit pattern stored is interpreted. Similarly, the type of a function determines how its return value is to be interpreted.

Types can be either predefined or derived. The predefined types in C are the basic types and the type void. The basic types consist of the integer types and the floating types.

1.3.1 Integer Types

There are five signed integer types: signed char, short int (or short), int, long int (or long), and long long int(*) (or long long(*)). For each of these types there is a corresponding unsigned integer type with the same storage size. The unsigned type is designated by the prefix unsigned in the type specifier, as in unsigned int.

The types char, signed char, and unsigned char are formally different. Depending on the compiler settings, however, char is equivalent either to signed char or to unsigned char. The prefix signed has no meaning for the types short, int, long, and long long(*), however, since they are always considered to be signed. Thus short and signed short specify the same type.

The storage size of the integer types is not defined; however, their width is ranked in the following order: char <= short <= int <= long <= long long(*). Furthermore, the size of type short is at least 2 bytes, long at least 4 bytes, and long long at least 8 bytes. Their value ranges for a given implementation are found in the header file limits.h.

ANSI C99 also introduces the type _Bool to represent Boolean values. The Boolean value true is represented by 1 and false by 0. If the header file stdbool.h has been included, then bool can be used as a synonym for _Bool and the macros true and false for the integer constants 1 and 0. Table 1-3 shows the standard integer types together with some typical value ranges.

Table 1-3. Standard integer types with storage sizes and value ranges

Type

Storage size

Value range (decimal)

_Bool

1 byte

0 and 1

char

1 byte

-128 to 127 or 0 to 255

unsigned char

1 byte

0 to 255

signed char

1 byte

-128 to 127

int

2 or 4 bytes

-32,768 to 32,767 or -2,147,483,648 to 2,147,483,647

unsigned int

2 or 4 bytes

0 to 65,535 or 0 to 4,294,967,295

short

2 bytes

-32,768 to 32,767

unsigned short

2 bytes

0 to 65,535

long

4 bytes

-2,147,483,648 to 2,147,483,647

unsigned long

4 bytes

0 to 4,294,967,295

long long(*)

8 bytes

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

unsigned long long(*)

8 bytes

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

ANSI C99 introduced the header file stdint.h(*), which defines integer types with specific widths (see Table 1-4). The width N of an integer type is the number of bits used to represent values of that type, including the sign bit. (Generally, N = 8, 16, 32, or 64.)

Table 1-4. Integer types with defined width

Type

Meaning

intN_t

Width is exactly N bits

int_leastN_t

Width is at least N bits

int_fastN_t

The fastest type with width of at least N bits

intmax_t

The widest integer type implemented

intptr_t

Wide enough to store the value of a pointer

For example, int16_t is an integer type that is exactly 16 bits wide, and int_fast32_t is the fastest integer type that is 32 or more bits wide. These types must be defined for the widths N = 8, 16, 32, and 64. Other widths, such as int24_t, are optional. For example:

int16_t val = -10;  // integer variable
                    // width: exactly 16 bits

For each of the signed types described above, there is also an unsigned type with the prefix u. uintmax_t, for example, represents the implementation's widest unsigned integer type.

1.3.2 Real and Complex Floating Types

Three types are defined to represent non-integer real numbers: float, double, and long double. These three types are called the real floating types .

The storage size and the internal representation of these types are not specified in the C standard, and may vary from one compiler to another. Most compilers follow the IEEE 754-1985 standard for binary floating-point arithmetic, however. Table 1-5 is also based on the IEEE representation.

Table 1-5. Real floating types

Type

Storage size

Value range(decimal, unsigned)

Precision (decimal)

float

4 bytes

1.2E-38 to 3.4E+38

6 decimal places

double

8 bytes

2.3E-308 to 1.7E+308

15 decimal places

long double

10 bytes

3.4E-4932 to 1.1E+4932

19 decimal places

The header file float.h defines symbolic constants that describe all aspects of the given representation (see Section 1.17).

1.3.2.1 Internal representation of a real floating-point number

The representation of a floating-point number x is always composed of a sign s, a mantissa m, and an exponent exp to base 2:

x = s * m * 2exp, where 1.0 <= m < 2  or  m = 0

The precision of a floating type is determined by the number of bits used to store the mantissa. The value range is determined by the number of bits used for the exponent.

Figure 1-2 shows the storage format for the float type (32-bit) in IEEE representation.

Figure 1-2. IEEE storage format for the 32-bit float type

figs/Cpr_02.gif

The sign bit S has the value 1 for negative numbers and 0 for other numbers. Because in binary the first bit of the mantissa is always 1, it is not represented. The exponent is stored with a bias added, which is 127 for the float type.

For example, the number -2.5 = -1 * 1.25 * 21 is stored as:

S = 1, Exponent = 1+127 = 128, Mantissa = 0.25
1.3.2.2 Complex floating types

ANSI C99 introduces special floating types to represent the complex numbers and the pure imaginary numbers. Every complex number z can be represented in Cartesian coordinates as follows:

z = x + i*y

where x and y are real numbers and i is the imaginary unit figs/squneg1.gif.

The real numbers x and y represent respectively the real part and the imaginary part of z.

Complex numbers can also be represented in polar coordinates:

z = r * (cos(theta) + i * sin(theta))

The angle theta is called the argument and the number r is the magnitude or absolute value of z.

In C, a complex number is represented as a pair of real and imaginary parts, each of which has type float, double, or long double. The corresponding complex floating types arefloat _Complex, double _Complex, and long double _Complex.

In addition, the pure imaginary numbers—i. e., the complex numbers z = i*y where y is a real number—can also be represented by the types float _Imaginary, double _Imaginary, and long double _Imaginary.

Together, the real and the complex floating types make up the floating types.

1.3.3 The Type void

The type specifier void indicates that no value is available. It is used in three kinds of situations:

Expressions of type void

There are two uses for void expressions. First, functions that do not return a value are declared as void. For example:

void exit (int status);

Second, the cast construction (void)expression can be used to explicitly discard the value of an expression. For example:

(void)printf("An example.");

Prototypes of functions that have no parameters

For example:

int rand(void);

Pointers to void

The type void * (pronounced "pointer to void") represents the address of an object, but not the object's type. Such "typeless" pointers are mainly used in functions that can be called with pointers to different types as parameters. For example:

void *memcpy(void *dest, void *source, size_t count);