HP OpenVMS SystemsC Programming Language
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 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.
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.
|Integral Types||Floating Point Types|
|signed short int||double|
|unsigned short int||long double|
|int||float _Complex (ALPHA, I64)|
|signed int||double _Complex (ALPHA, I64)|
|unsigned int||long double _Complex (ALPHA, I64)|
In HP C, use of the _Imaginary keyword produces a warning, which is resolved by treating it as an ordinary identifier.
|signed long int|
|unsigned long int|
|long long int (ALPHA, I64)|
|signed long long int (ALPHA, I64)|
|unsigned long long int (ALPHA, I64)|
|Integral Character Types|
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 :
There are also the type-qualifier keywords:
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.
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.
|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, I64), signed __int64 (ALPHA, I64)||64 bits||- 9223372036854775808 to 9223372036854775807|
|unsigned long long int (ALPHA, I64), unsigned __int64 (ALPHA, I64)||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, I64)||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.
The integral types are:
For HP 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 HP 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 and Itanium 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 */
HP 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 .
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 -2n-1 to 2n-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.
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:
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 = 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.9.3 has more information on the syntactic rules of using strings; Chapter 4 has information on declaring string literals.