Tru64 UNIX
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:

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  
signed int  
unsigned int  
long int  
signed long int  
unsigned long int  
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 :

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.

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 __int64 (ALPHA) 64 bits --9223372036854775808 to 9223372036854775807
unsigned __int64 (ALPHA) 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:

The integral types are:

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 __int64 and unsigned __int64 are provided on Alpha processors.

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 .

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:

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.

3.3 Floating-Point Types

The three floating-point types are:

Use the floating-point types for variables, constants, and function return values with fractional parts, or where the value exceeds the storage range available with the integral types. The following examples show sample floating-point type declarations (and initializations):


float x = 35.69; 
double y = .0001; 
double z = 77.0e+10; 
float Q = 99.9e+99;                 /*  Exceeds allowable range   */ 

3.4 Derived Types

There are five derived types in C:

The following sections describe these derived types.

A derived type is formed by using one or more basic types in combination. Using derived types, an infinite variety of new types can be formed. The array and structure types are collectively called the aggregate types. Note that the aggregate types do not include union types, but a union may contain an aggregate member.

3.4.1 Function Type

A function type describes a function that returns a value of a specified type. If the function returns no value, it should be declared as "function returning void " as follows:


void function1 (); 

In the following example, the data type for the function is "function returning int ":


int uppercase(int lc) 
{ 
  int uc = lc + 0X20; 
  return uc; 
} 

Chapter 4 discusses declarations in general. Chapter 5 covers functions specifically, including their declarations, parameters, and argument passing.

3.4.2 Pointer Type

A pointer type describes a value that represents the address of an object of a stated type. A pointer is stored as an integral value that references the address of the target object. Pointer types are derived from other types, called the referenced type of the pointer. For example:


int *p;          /*  p is a pointer to an int type                 */ 
double *q();     /*  q is a function returning a pointer to an 
                     object of type double                         */ 
int (*r)[5];     /*  r is a pointer to an array of five elements   */ 
                 /*  (r holds the address to the first element of 
                     the array)                                    */ 
const char s[6]; /*  s is a const-qualified array of 6 elements    */ 

The pointer itself can have any storage class, but the object addressed by the pointer cannot have the register storage class or be a bit field. Pointers to qualified or unqualified versions of compatible types have the same representation and alignment requirements as the target type. Pointers to other types need not have the same representation or alignment requirements.

The construction void * designates a generic "pointer to void " type. The void * construction can be used to point to an object of any type, and it is most useful when a pointer is needed to point to the address of objects with different or unknown types (such as in a function prototype). A pointer to void can also be converted to or from a pointer of any other type, and has the same representation and alignment requirements as a pointer to a character type.

A pointer to the address 0 (zero) is called a null pointer. Null pointers are often used to indicate that no more members of a list exist (for example, when using pointers to show the next member of the list). Dereferencing a null pointer with the * or subscripting operators leads to unpredictable and usually very unfavorable results.

See Chapter 4 for details on the syntax of pointer declarations.


Previous Next Contents Index