United States

Compaq C

# Compaq C
Language Reference Manual

Previous | Contents | Index

# 6.11 Data-Type Conversions

C performs data-type conversions in the following four situations:

- When two or more operands of different types appear in an expression.
- When arguments of type `char` , `short` , and `float` are passed to a function using the old style declaration.
- When arguments that do not conform exactly to the parameters declared in a function prototype are passed to a function.
- When the data type of an operand is deliberately converted by the cast operator. See Section 6.4.6 for more information on the cast operator.

The following sections describe how operands and function arguments are converted.

## 6.11.1 Usual Arithmetic Conversions

The following rules---referred to as the usual arithmetic conversions---govern the conversion of all operands in arithmetic expressions. The effect is to bring operands to a common type, which is also the type of the result. The rules govern in the following order:

1. If either operand is not of arithmetic type, no conversion is performed.
2. If either operand has type `long double` , the other operand is converted to `long double` .
3. Otherwise, if either operand has type `double` , the other operand is converted to `double` .
4. Otherwise, if either operand has type `float` , the other operand is converted to `float` .
5. For complex numbers ( (ALPHA ONLY)), the above conversions take place for the corresponding real type of the operand to be converted.
   For example, adding a `double _Complex` and a `float` , converts just the `float` operand to `double` , yielding a `double _Complex` result.
6. Otherwise, the integer promotions are performed on both operands, and the following rules apply:
   1. If both operands have the same type, then no further conversion is needed.
   2. Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
   3. Otherwise, If either operand has type `unsigned long long int` , the other operand is converted to `unsigned long long int` .
   4. If either operand has type `unsigned long int` , the other operand is converted to `unsigned long int` .
   5. Otherwise, if one operand has type `long int` and the other has type `unsigned int` , and if a `long int` can represent all values of an `unsigned int` , the operand of type `unsigned int` is converted to `long int` . If a `long int` cannot represent all the values of an `unsigned int` , both operands are converted to `unsigned long int` .
   6. Otherwise, if either operand has type `long int` , the other operand is converted to `long int` .
   7. Otherwise, if either operand has type `unsigned int` , the other operand is converted to `unsigned int` .
   8. Otherwise, both operands have type `int` .

The following sections elaborate on the usual arithmetic conversion rules.

### 6.11.1.1 Characters and Integers

A `char` , `short int` , or `int` bit field, either signed or unsigned, or an object that has enumeration type, can be used in an expression wherever an `int` or `unsigned int` is permitted. If an `int` can represent all values of the original type, the value is converted to an `int` . Otherwise, it is converted to an `unsigned int` . These conversion rules are called the integer promotions.

This implementation of integer promotion is called value preserving, as opposed to unsigned preserving in which `unsigned char` and `unsigned short` widen to `unsigned int` . Compaq C uses value-preserving promotions, as required by the ANSI C standard, unless the common C mode is specified.

To help locate arithmetic conversions that depend on unsigned preserving rules, Compaq C, with the check option enabled, flags any integer promotions of `unsigned char` and `unsigned short` to `int` that could be affected by the value-preserving approach for integer promotions.

All other arithmetic types are unchanged by the integer promotions.

In Compaq C, variables of type `char` are bytes treated as signed integers. When a longer integer is converted to a shorter integer or to `char` , it is truncated on the left; excess bits are discarded. For example:

    int i;
    char c;

    i = 0xFFFFFF41;
    c = i;

This code assigns hex 41 ( `'A'` ) to `c` . The compiler converts shorter signed integers to longer ones by sign extension.

### 6.11.1.2 Signed and Unsigned Integers

Conversions also take place between the various kinds of integers.

When a value with an integral type is converted to another integral type (such as `int` converted to `long int` ) and the value can be represented by the new type, the value is unchanged.

When a signed integer is converted to an unsigned integer of equal or greater size, and the signed integer value is nonnegative, its value is unchanged. If the signed integer value is negative, then:

- If the unsigned integer type is larger, the signed integer is first promoted to the signed integer that corresponds to the unsigned integer; then the value is converted to unsigned by adding to it one greater than the largest number that can be represented in the unsigned integer type.
- If the unsigned integer type is equal or smaller than the signed integer type, then the value is converted to unsigned by adding to it one greater than the largest number that can be represented in the unsigned integer type.

When an integer value is demoted to an unsigned integer of smaller size, the result is the nonnegative remainder of the value divided by the number one greater than the largest representable unsigned value for the new integral type.

When an integer value is demoted to a signed integer of smaller size, or an unsigned integer is converted to its corresponding signed integer, the value is unchanged if it is small enough to be represented by the new type. Otherwise, the result is truncated; excess high-order bits are discarded and precision is lost.

Conversion between integral types of the same size, whether signed or unsigned, results in no machine-level representation change.

### 6.11.1.3 Floating and Integral

When a floating-type operand is converted to an integer, the fractional part is discarded.

When a floating-type value is to be converted at compile time to an integer or another floating type, and the result cannot be represented, the compiler reports a warning in the following instances:

- The conversion is to `unsigned int` and the result cannot be represented by the `unsigned int` type.
- The conversion is to a type other than `unsigned int` , and the result cannot be represented by the `int` type.

When a value of integral type is converted to floating type, and the value is in the range of values that can be represented, but not exactly, the result of the conversion is either the next higher or next lower value, whichever is the natural result of the conversion on the hardware. See your Compaq C documentation for the conversion result on your platform.

### 6.11.1.4 Floating Types

If an operand of type `float` appears in an expression, it is treated as a single-precision object unless the expression also involves an object of type `double` or `long double` , in which case the usual arithmetic conversion applies.

When a `float` is promoted to `double` or `long double` , or a `double` is promoted to `long double` , its value is unchanged.

The behavior is undefined when a `double` is demoted to `float` , or a `long double` to `double` or `float` , if the value being converted is outside the range of values that can be represented.

If the value being converted is inside the range of values that can be represented, but not exactly, the result is rounded to either the next higher or next lower representable `float` value.

## 6.11.2 Pointer Conversions

Although two types (for example, `int` and `long` ) can have the same representation, they are still different types. This means that a pointer to `int` cannot be assigned to a pointer to `long` without using a cast. Nor can a pointer to a function of one type be assigned to a pointer to a function of a different type without using a cast. In addition, pointers to functions that have different parameter-type information, including the old-style absence of parameter-type information, are different types. In these instances, if a cast is not used, the compiler issues an error. Because there are alignment restrictions on some target processors, access through an unaligned pointer can result in a much slower access time or a machine exception.

A pointer to `void` can be converted to or from a pointer to any incomplete or object type. If a pointer to any incomplete or object type is converted to a pointer to `void` and back, the result compares equal to the original pointer.

An integral constant expression equal to 0, or such an expression cast to the `void *` type, is called a null pointer constant. If a null pointer constant is assigned to or compared for equality with a pointer, the constant is converted to a pointer of that type. Such a pointer is called a null pointer, and is guaranteed to compare unequal to a pointer to any object or function.

An array designator is automatically converted to a pointer to the array type, and the pointer points to the first element of the array.

## 6.11.3 Function Argument Conversions

The data types of function arguments are assumed to match the types of the formal parameters unless a function prototype declaration is present. In the presence of a function prototype, all arguments in the function invocation are compared for assignment compatibility to all parameters declared in the function prototype declaration. If the type of the argument does not match the type of the parameter but is assignment compatible, C converts the argument to the type of the parameter (see Section 6.11.1). If an argument in the function invocation is not assignment compatible to a parameter declared in the function prototype declaration, an error message is generated.

If a function prototype is not present, all arguments of type `float` are converted to `double` , all arguments of type `char` or `short` are converted to type `int` , all arguments of type `unsigned char` and `unsigned short` are converted to `unsigned int` , and an array or function name is converted to the address of the named array or function. The compiler performs no other conversions automatically, and any mismatches after these conversions are programming errors.

A function designator is an expression that has function type. Except when it is the operand of the `sizeof` operator or the unary & operator, a function designator with type "function returning type" is converted to an expression that has type "pointer to function returning type."

# Chapter 7
Statements

This section describes the following kinds of statements in the C programming language. Except as indicated in this chapter, statements are executed in the sequence in which they appear in a function body:

- Labeled statements ( Section 7.1)
- Compound statements ( Section 7.2)
- Expression statements ( Section 7.3)
- Null statements ( Section 7.4)
- Selection statements ( Section 7.5)
- Iteration statements ( Section 7.6)
- Jump statements ( Section 7.7)

# 7.1 Labeled Statements

A label is an identifier used to flag a location in a program as the target of a `goto` statement or `switch` statement. A label has the following syntax:

`identifier : statement case constant-expression : statement default : statement`

The scope of the label is the containing function body. Variables can have the same name as a label in the function because labels and variables have different name spaces (see Section 2.15).

There are three kinds of labeled statements in C:

- Any statement preceded by a label
- A `case` statement
- A `default` statement

The last two statements are discussed in Section 7.5.2 because they can appear only within a `switch` statement.

# 7.2 Compound Statements

A compound statement, or block, allows a sequence of statements to be treated as a single statement. A compound statement begins with a left brace, contains any mix of declarations and statements, and ends with a right brace, as shown in the following example:

     {
        int a;
        a = 1;
        int b;
        b = 2;
     }

Note The ability to mix declarations and statements in any sequence in a compound statement is not allowed in common C, VAX C, and Strict ANSI89 modes. In these modes, the declarations must be specified first, followed by the statements.

Block declarations are local to the block, and, for the rest of the block, they supersede other declarations of the same name in outer scopes.

A block is entered normally when control flows into it, or when a `goto` statement transfers control to a label at the beginning of the block itself. Each time the block is entered normally, storage is allocated for `auto` or `register` variables. If, on the other hand, a `goto` statement transfers control to a label inside the block or if the block is the body of a `switch` statement, these storage allocations do not occur. For more information about storage classes, see Section 2.10.

Function definitions contain compound statements. The compound statement following the parameter declarations in a function definition is called the function body.

# 7.3 Expression Statements

Any valid expression can be used as a statement by following the expression with a semicolon, as shown in the following example:

    i++;

This statement increments the value of the variable `i` . Note that `i++` is a valid C expression that can appear in more complex C statements. For more information about the C expressions, see Chapter 6.

# 7.4 Null Statements

A null statement is used to provide a null operation in situations where the grammar of the language requires a statement, but the program requires no work to be done. The null statement consists of a semicolon:

;

``

The null statement is useful with the `if` , `while` , `do` , and `for` statements. The most common use of this statement is in loop operations in which all the loop activity is performed by the test portion of the loop. For example, the following statement finds the first element of an array that has a value of 0:

    for (i=0; array[i] != 0; i++)
       ;

In this example, the `for` statement is executed for its side effects only; the loop body is a null statement. See Section 7.6 for more information about iteration statements.

The null statement is also useful where a label is needed just before a brace that terminates a compound statement. (A label cannot immediately precede the right brace; it must always be attached to a statement.) For example:

    if (expression1)
    {
      ...

      goto label_1;  /* Terminates this part of the if statement */
      ...

    label_1: ;
    }
    else ...

# 7.5 Selection Statements

A selection statement selects among a set of statements depending on the value of a controlling expression. The selection statements are the `if` statement and the `switch` statement, which are discussed in the following sections.

## 7.5.1 The if Statement

The `if` statement has the following syntax:

`if ( expression ) statement`

`elseopt else-statementopt`

The statement following the control expression is executed if the value of the control expression is true (nonzero). An `if` statement can be written with an optional `else` clause that is executed if the control expression is false (0).

Consider the following example:

    if (i < 1)
       funct(i);
    else
       {
       i = x++;
       funct(i);
       }

In this example, if the value of `i` is less than 1, then the statement `funct(i)` is executed and the compound statement following the keyword `else` is not executed. If the value of `i` is not less than 1, then only the compound statement following the keyword `else` is executed.

The control expression in a selection statement is usually a logical expression, but it can be any expression of scalar type.

When `if` statements are nested, an `else` clause matches the most recent `if` statement that does not have an `else` clause, and is in the same block. For example:

    if (i < 1)
        {
        if (j < 1)
            funct(j);
        if (k < 1)            /* This if statement is associated with */
            funct(k);
        else                  /* this else clause.                    */
            funct(j + k);
        }

## 7.5.2 The switch Statement

The `switch` statement executes one or more of a series of cases, based on the value of a controlling expression. The `switch` statement has the following syntax:

`switch ( expression ) statement`

The usual arithmetic conversions are performed on the control expression, but the result must have an integral type. For more information about data-type conversion, see Section 6.11. The `switch` statement is typically a compound statement, within which are one or more `case` statements executed if the control expression matches the `case` . The syntax for a `case` label and expression follows:

`case constant-expression : statement`

The constant expression must have an integral type. No two `case` labels can specify the same value. There is no limit on the number of `case` labels in a `switch` statement.

Only one statement in the compound statement can have the following label:

`default :`

The `case` and `default` labels can occur in any order, but it is common practice for the `default` statement to follow the `case` statements. Note that execution flows from the selected case into the cases following unless explicit action is taken, such as a `break` statement.

When the `switch` statement is executed, the following sequence takes place:

1. The `switch` control expression is evaluated (and integral promotions applied) and compared with the constant expressions in the `case` labels.
2. If the control expression's value matches a `case` label, control transfers to the statement following that label. If a `break` statement is encountered, the `switch` statement terminates; otherwise, execution continues into the following `case` or default statements until a `break` statement or the end of the `switch` statement is encountered (see Example 7-1).
   A `switch` statement can also be terminated by a `return` or `goto` statement. If a `switch` statement is inside a loop, the `switch` statement is terminated if a `continue` statement terminates the loop. See Section 7.7 for more information about these statements.
3. If the control expression's value does not match any `case` label, and there is a `default` label, control is transferred to the statement following that label. If a `break` statement does not end the `default` statement, and a `case` label follows, that `case` statement is executed.
4. If the control expression's value does not match any `case` label and there is no `default` label, execution of the `switch` statement terminates.

Example 7-1 uses the `switch` statement to count blanks, tabs, and new-line characters entered from the terminal.

Example 7-1 Using switch to Count Blanks, Tabs, and New Lines

    /*  This program counts blanks, tabs, and new lines in text *
     *  entered from the keyboard.                              */

    #include <stdio.h>
    main()
    {
       int number_tabs = 0, number_lines = 0, number_blanks = 0;
       int ch;
       while ((ch = getchar()) != EOF)
          switch (ch)
             {
    (1)            case '\t':  ++number_tabs;
    (2)                        break;
                case '\n':  ++number_lines;
                            break;
                case ' ' :  ++number_blanks;
                            break;
                default:;
             }
       printf("Blanks\tTabs\tNewlines\n");
       printf("%6d\t%6d\t%6d\n", number_blanks,
                                 number_tabs,number_lines);
    }

Key to Example 7-1:

Previous | Next | Contents | Index

privacy and legal statement