HPlogo HP C/HP-UX Reference Manual: Version A.05.55.02 > Chapter 5 Expressions and Operators

Cast Operator

» 

Technical documentation

Complete book in PDF

 » Table of Contents

 » Index

Syntax

(data_type) exp

Arguments

data_type

Any scalar data type, including a scalar data type created through a typedef. The data_type cannot be an aggregate type, but it can be a pointer to an aggregate type.

exp

Any scalar expression.

Description

To cast a value means to explicitly convert it to another data type. For example, given the two definitions:

int y = 5;
float x;

The following cast operation casts the value of y to float:

x = (float) y; /* x now equals 5.0 */

Here are four more casts (assume that j is a scalar data type):

i = (float) j; /* Cast j's value to float */
i = (char *)j; /* Cast j's value to a pointer to a char */
i = ((int *)())j;/* Cast j's value to a pointer to a function
returning an int */
i = (float) (double) j; /* Cast j's value first to a double
and then to a float */

It is important to note that if exp is a variable, a cast does not change this variable's data type; it only changes the type of the variable's value for that one expression. For instance, in the preceding casting examples, the cast does not produce any permanent effect on variable j.

There are no restrictions on casting from one scalar data type to another, except that you may not cast a void object to any other type. You should be careful when casting integers to pointers. If the integer value does not represent a valid address, the results are unpredictable.

A cast expression may not be an lvalue.

Casting Integers to Other Integers

It is possible to cast one integer into an integer of a different size and to convert a floating-point value, enumeration value or pointer to an integer. Conversions from one type of integer to another fall into five cases (A-E) as shown:

Table 5-9 Integer Conversions

Original Type

char

short

int

unsigned char

unsigned short

unsigned int

char

A

B

B

D

E

E

short

C

A

BCDE

int (long)*

C

C

A*

C

CD*

unsigned char

D

B

B

A

B

B

unsigned short

C

D

B

C

A

B

unsigned int

C

C

D

C

C

A

 

* Case C for long in 64-bit mode.

CASE A: Trivial Conversions

It is legal to convert a value to its current type by casting it, but this conversion has no effect.

CASE B: Integer Widening

Casting an integer to a larger size is fairly straightforward. The value remains the same, but the storage area is widened. The compiler preserves the sign of the original value by filling the new leftmost bits with ones if the value is negative, or with zeros if the value is positive. When it converts to an unsigned integer, the value is always positive, so the new bits are always filled with zeros. The following table illustrates this principle.

hex dec
char i = 37 55
(short) i => 0037 55
(int) i => 00000037 55

char j = c3 -61
(short) j => ffc3 -61
(int) j => ffffffc3 -61

unsigned char k = 37 55
(short) k => 0037 55
(int) k => 00000037 55

CASE C: Casting Integers to a Smaller Type

When an int value is cast to a narrower type (short or char), the excess bits on the left are discarded. The same is true when a short is cast to a char, or when a long in 64-bit mode is cast to an int. For instance, if an int is cast to a short, the 16 leftmost bits are truncated. The following table of values illustrates these conversions.

hex dec
signed long int i = cf34bf1 217271281

(signed short int)i => 4bf1 19441
(signed char)i => f1 -15
(unsigned char)i => f1 241

If, after casting to a signed type, the leftmost bit is 1, then the number is negative. However, if you cast to an unsigned type and after the shortening the leftmost bit is 1, then that 1 is part of the value (it is not the sign bit).

CASE D: Casting from Signed to Unsigned, and Vice Versa

When the original type and the converted type are the same size, a representation change is necessary. That is, the internal representation of the value remains the same, but the sign bit is interpreted differently by the compiler. For instance:

hex dec hex dec
signed int i = fffffca9 -855 0000f2a1 62113

(unsigned int)i => fffffca9 4294966441 0000f2a1 62113

The hexadecimal notation shows that the numbers are the same internally, but the decimal notation shows that the compiler interprets them differently.

CASE E: Casting Signed to Unsigned and Widening

This case is equivalent to performing two conversions in succession. First, the value is converted to the signed widened type as described in case B, and then it is converted to unsigned as described in case D. In the following assignments, the new leftmost bits are filled with ones to preserve negativeness even though the final value is unsigned.

hex dec
signed short int i = ff55 -171

(unsigned long int)i => fffff55 4294967125

Casting Floating-Point Values to Integers

Casting floating-point values to integers may produce useless values if an overflow condition occurs. The conversion is made simply by truncating the fractional part of the number. For example, the floating-point value 3.712 is converted to the integer 3, and the floating-point value -504.2 is converted to -504.

Here are some more examples:

float f = 3.700, f2 = -502.2, f3 = 7.35e9;

(int)f => 3
(unsigned int)f => 3
(char)f => 3

(int)f2 => -502 in decimal fffffe0a in hex
(unsigned int)f2 => 4294966794 in decimal or fffffe0a in hex
(char)f2 => 10 in decimal 0a in hex

(int)f3 => run-time error
(unsigned int)f3 => run-time error
(char)f3 => run-time error

NOTE: Converting a large float to a char produces unpredictable results if the rounded value cannot fit in one byte. If the value cannot fit in four bytes, the run-time system issues an overflow error.

Casting Enumerated Values to Integers

When you cast an enumerated expression, the conversion is performed in two steps. First, the enumerated value is converted to an int, and then the int is converted to the final target data type. The sign is preserved during these conversions.

Casting Double to Float and Vice Versa

When you cast a float to a double, the system extends the number's precision without changing its true value. However, when you cast a double to a float, the system shrinks the number's precision, and this shrinking may change the number's value because of rounding. The rounding generally occurs on the sixth or seventh decimal digit. Also, when you cast down from double to float, you run the risk of causing a run-time overflow error caused by a double that is too big or too small to fit in a float.

Casting Pointers to Pointers

You may cast a pointer of one type to a pointer to any other type. For example:

int *int_p;
float *float_p;
struct S *str_p;
extern foo(struct T *);
    . . .
int_p = (int *) float_p;
float_p = (float *) str_p;
foo((struct T *) str_p);

The cast is required whenever you assign a pointer value to a pointer variable that has a different base type, and when you pass a pointer value as a parameter to a function that has been prototyped with a different pointer type. The only exception to this rule concerns the generic pointer. You may assign any pointer value to a generic pointer without casting.

© Hewlett-Packard Development Company, L.P.