United States

Compaq C

# Compaq C
Language Reference Manual

Previous | Contents | Index

# Chapter 3
Data Types

The type of a data object in C determines the range and kind of values an object can represent, the size of machine storage reserved for an object, and the operations allowed on an object. Functions also have types, and the function's return type and parameter types can be specified in the function's declaration.

The following sections discuss these topics:

- Data sizes ( Section 3.1)
- Integral types ( Section 3.2)
- Floating-point types ( Section 3.3)
- Derived types ( Section 3.4), including:
  - Function type ( Section 3.4.1)
  - Pointer type ( Section 3.4.2)
  - Array type ( Section 3.4.3)
  - Structure type ( Section 3.4.4)
  - Union type ( Section 3.4.5)
- `void` type ( Section 3.5)
- Enumerated types ( Section 3.6)
- Type qualifiers ( Section 3.7)
- Type definition ( Section 3.8)

The selection of a data type for a given object or function is one of the fundamental programming steps in any language. Each data object or function in the program must have a data type, assigned either explicitly or by default. (Chapter 4 discusses the assignment of a data type to an object.) C offers a wide variety of types. This diversity is a strong feature of C, but can be initially confusing.

To help avoid this confusion, remember that C has only a few basic types. All other types are derived combinations of these basic types. Some types can be specified in more than one way; for example, `short` and `short int` are the same type. (In this manual, the longest, most specific name is always used.) Type is assigned to each object or function as part of the declaration. Chapter 4 describes declarations in more detail.

Table 3-1 lists the basic data types: integral types (objects representing integers within a specific range), floating-point types (objects representing numbers with a significand part---a whole number plus a fractional number---and an optional exponential part), and character types (objects representing a printable character). Character types are stored as integers.

Note Enumerated types are also normally classified as integral types, but for the purposes of clarity they are not listed here. See Section 3.6 for more information.

Table 3-1 Basic Data Types
Integral Types | Floating Point Types
--- | ---
`short int` | `float`
`signed short int` | `double`
`unsigned short int` | `long double`
`int` | `float _Complex` (ALPHA ONLY)
`signed int` | `double _Complex` (ALPHA ONLY)
`unsigned int` | `long double _Complex` (ALPHA ONLY)
`_Imaginary` In Compaq C, use of the `_Imaginary` keyword produces a warning, which is resolved by treating it as an ordinary identifier. |
`long int` |
`signed long int` |
`unsigned long int` |
`long long int` (ALPHA ONLY) |
`signed long long int` (ALPHA ONLY) |
`unsigned long long int` (ALPHA ONLY) |
`_Bool` |
Integral Character Types |
`char` |
`signed char` |
`unsigned char` |

The integral and floating-point types combined are called the arithmetic types. See Section 3.1 for information about the size and range of integral and floating-point values.

A large variety of derived types can be created from the basic types. Section 3.4 discusses the derived types.

Besides the basic and derived types, there are three keywords that specify unique types: `void` , `enum` , and `typedef` :

- The `void` keyword specifies a special type indicating no value, or it can be used with the pointer operator (*) to indicate a generic pointer type. See Section 3.5 for more information on the `void` type.
- The `enum` keyword specifies an integer type of your own design, specifying the acceptable values of the type to a predefined set of named integer constant values. Enumerated types are stored as integers. See Section 3.6 for a detailed description of enumerated types.
- The `typedef` keyword specifies a synonym for a type made from one or more basic or derived types. See Section 3.8 for more information on creating type definitions.

There are also the type-qualifier keywords:

- `const` , used to prevent write access to an object (see Section 3.7.1)
- `volatile` , used to restrict the optimizations that might otherwise be performed on references to an object (see Section 3.7.2)
- `__unaligned` (ALPHA), used in pointer definitions, to indicate to the compiler that the data pointed to is not properly aligned on a correct address
- `__restrict` (for pointer type only), used to designate a pointer as pointing to a distinct object, thus allowing compiler optimizations to be made (see Section 3.7.4)

Using a qualifying keyword in the type declaration of an object results in a qualified type. See Section 3.7 for general information on type qualifiers.

With such a wide variety of types, operations in a program often need to be performed on objects of different types, and parameters of one type often need to be passed to functions expecting different parameter types. Because C stores different kinds of values in different ways, a conversion must be performed on at least one of the operands or arguments to convert the type of one operand or argument to match that of the other. You can perform conversions explicitly through casting, or implicitly through the compiler. See Section 6.11 for more information on data-type conversions. See Section 2.7 for a description of type compatibility.

See your platform-specific Compaq C documentation for a description of any implementation-defined data types.

# 3.1 Data Sizes

An object of a given data type is stored in a section of memory having a discreet size. Objects of different data types require different amounts of memory. Table 3-2 shows the size and range of the basic data types.

Table 3-2 Sizes and Ranges of Data Types
Type | Size | Range
--- | --- | ---
Integral Types
`short int` , or `signed short int` | 16 bits | --32768 to 32767
`unsigned short int` | 16 bits | 0 to 65535
`int` or `signed int` | 32 bits | --2147483648 to 2147483647
`unsigned int` | 32 bits | 0 to 4294967295
`long int` , or `signed long int` (OPENVMS) | 32 bits | --2147483648 to 2147483647
`long int` , or `signed long int` (TRU64 UNIX) | 64 bits | --9223372036854775808 to 9223372036854775807
`unsigned long int` (OPENVMS) | 32 bits | 0 to 4294967295
`unsigned long int` (TRU64 UNIX) | 64 bits | 0 to 18446744073709551615
`signed long long int` (ALPHA ONLY), `signed __int64` (ALPHA ONLY) | 64 bits | --9223372036854775808 to 9223372036854775807
`unsigned long long int` (ALPHA ONLY), `unsigned __int64` (ALPHA ONLY) | 64 bits | 0 to 18446744073709551615
Integral Character Types
`char` and `signed char` | 8 bits | --128 to 127
`unsigned char` | 8 bits | 0 to 255
`wchar_t` | 32 bits | 0 to 4294967295
Floating-Point Types (range is for absolute value)
`float` | 32 bits | 1.1 x 10 -38 to 3.4 x 10 38
`double` | 64 bits | 2.2 x 10 -308 to 1.7 x 10 308
`long double` (OPENVMS ALPHA) | 128 bits | 3.4 x 10 -49321 to 1.2 x 10 1049321
`long double` (OPENVMS VAX, TRU64 UNIX) | Same as `double` | Same as `double`

Derived types can require more memory space.

See your platform-specific Compaq C documentation for the sizes of implementation-defined data types.

# 3.2 Integral Types

In C, an integral type can declare:

- Integer values, signed or unsigned
- Boolean values, where 0 is equivalent to false and any nonzero number is equivalent to true
- Characters, which are automatically converted to an integer value by the compiler
- Members of an enumerated type, which are interpreted as an integer by the compiler
- Bit fields

The integral types are:

- `char` , `signed char` , `unsigned char` ---8 bits
- `short int` , `signed short int` , and `unsigned short int` ---16 bits
- `_Bool` ---1 byte
- `int` , `signed int` , `unsigned int` ---32 bits
- `long int` , `signed long int` , and `unsigned long int` ---32 bits (OPENVMS)
- `long int` , `signed long int` , and `unsigned long int` ---64 bits (TRU64 UNIX)
- `signed long long int` (ALPHA ONLY) and `unsigned long long int` (ALPHA ONLY)---64 bits
- `signed __int64` (ALPHA ONLY) and `unsigned __int64` (ALPHA ONLY)---64 bits
- `enum` ---32 bits

## 3.2.1 Non-Character Types

For Compaq C on OpenVMS systems, storage for `int` and `long` is identical. Similarly, storage of `signed int` and `signed long` is identical, and storage for `unsigned int` and `unsigned long` is identical.

For Compaq C on Tru64 UNIX systems, storage for the `int` data types is 32 bits, while storage for the `long int` data types is 64 bits.

The 64-bit integral types `signed long long int` and `unsigned long long int` , and their equivalents `signed __int64` and `unsigned __int64` are provided on Alpha processors only. Note: the `__int64` and `long long int` data types (both signed and unsigned) can be used interchangeably, except for use with pointer operations, in which case the pointer types must be identical:

    __int64 *p1;
    __int64 *p2;
    long long int *p3;
       .
       .
       .
    p1 = p2;        // valid
    p1 = p3;        // invalid

For each of the signed integral types, there is a corresponding unsigned integral type that uses the same amount of storage. The `unsigned` keyword with the integral type modifies the way the integer value is interpreted, which allows the storage of a larger range of positive values. When using the `unsigned` keyword, the bits are interpreted differently to allow for the increased positive range with the unsigned type (at the expense of the negative range of values). For example:

    signed short int x = 45000;  /*  ERROR -- value too large for short int  */
    unsigned short int y = 45000;/*  This value is OK                        */

The range of values for the `signed short int` type is --32,768 to 32,767. The range of values for the `unsigned short int` type is 0 to 65,535.

A computation involving unsigned operands can never overflow, because any result outside the range of the `unsigned` type is reduced to fit the type by the rules of modulus arithmetic. If the result cannot be represented by the resulting integer type, the result is reduced modulo the number that is one greater than the largest value that can be represented by the resulting unsigned integer type. This means that the low-order bits are kept, and the high-order bits of the mathematical result that do not fit in the type of the result are discarded. For example:

    unsigned short int z = (99 * 99999); /*  Value of y after evaluation is 3965  */

Compaq C treats the plain `char` type as `signed` by default for compatibility with VAX C and many other C compilers. However, a command-line option can control this, and a predefined macro can be tested to determine the setting of the option in a given compilation. On Alpha systems, `unsigned char` might offer some performance advantage for character-intensive processing.

An unsigned integer of n bits is always interpreted in straight unsigned binary notation, with possible values ranging from 0 to 2 n-1 .

Note The interpretation of signed integers depends on the size of machine representation and the encoding technique used on the machine. With two's-complement representation, signed integers of n bits have a range of --2 n-1 to 2 n-1-1 .

The C99-specified `_Bool` data type is available in all modes of the compiler except VAX C, common, and strict ANSI89 modes. A `_Bool` object occupies a single byte of storage and is treated as an `unsigned integer` , but its value can be only 0 or 1.

- Notes A bit field can be declared to be type `_Bool` . A pointer can be converted to a `_Bool` type. When any scalar value is converted to `_Bool` , the result is 0 if the value compares equal to 0 (for example, if the pointer is NULL). Otherwise, the result is 1. This is one way the `_Bool` type is different than the other integer types. In the following example, the value of `b` is zero, but the value of `c` is 1:
      double a = .01;
      int b = a;
      _Bool c = a;
- The `_Bool` type is intended to be used in conjuction with a new standard header, `<stdbool.h>` , but that is not required. The content of the new header is:
      #define bool _Bool
      #define true 1
      #define false 0
      #define __bool_true_false_are_defined 1
Also see Section 9.11.

## 3.2.2 Character Types

Character types are declared with the keyword `char` and are integral types. Using `char` objects for nonintegral operations is not recommended, as the results are likely to be nonportable. An object declared as a `char` type can always store the largest member of the source character set.

Valid character types are:

- `char`
- `signed char`
- `unsigned char`
- `wchar_t`

The wide character type `wchar_t` is provided to represent characters not included in the ASCII character set. The `wchar_t` type is defined using the `typedef` keyword in the `<stddef.h>` header file. Wide characters used in constants or strings must be preceded with an `L` . For example:

    #include <stddef.h>

    wchar_t a[6] = L"Hello";

All `char` objects are stored in 8 bits. All `wchar_t` objects are stored as `unsigned int` objects in 32 bits. The value of a given character is determined by the character set being used. In this text, the ASCII character set is used in all examples. See Appendix C for a complete list of ASCII equivalents, in decimal, octal, and hexadecimal radixes.

To aid portability, declare `char` objects that will be used in arithmetic as `signed char` or `unsigned char` . For example:

    signed char letter;
    unsigned char symbol_1, symbol_2;
    signed char alpha = 'A';  /* alpha is declared and initialized as 'A' */

Strings are arrays of characters terminated by the null character (\0). Section 1.8.3 has more information on the syntactic rules of using strings; Chapter 4 has information on declaring string literals.

Previous | Next | Contents | Index

privacy and legal statement