[an error occurred while processing this directive]

HP OpenVMS Systems

C Programming Language
Content starts here HP C

HP 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:

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, I64)
signed int double _Complex (ALPHA, I64)
unsigned int long double _Complex (ALPHA, I64)
_Imaginary

In HP 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, I64)  
signed long long int (ALPHA, I64)  
unsigned long long int (ALPHA, I64)  
_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, except in the compiler's RELAXED mode, in which other types are allowed. 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, I64), 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 HP 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, 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.

See your platform-specific HP 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, I64) and unsigned long long int (ALPHA, I64)---64 bits
  • signed __int64 (ALPHA, I64) and unsigned __int64 (ALPHA, I64)---64 bits
  • enum ---32 bits

3.2.1 Non-Character Types

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 .

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 -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.

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.9.3 has more information on the syntactic rules of using strings; Chapter 4 has information on declaring string literals.


Previous Next Contents Index