Sign Extension

“Sign extension” is the propagation of the sign bit to fill unoccupied space when promoting to a more-significant type or when performing bitwise right-shift operations.

Promotion from Shorter Types

Integral promotions from shorter types occur when you make an assignment, perform arithmetic, perform a comparison, or perform an explicit cast.

The behavior of integral promotion is well defined, except for type char. The implementation defines whether type char is treated as signed or unsigned. The following code fragment is an example of promotion as a result of assignment:

char c1 = -3;

int i1;

i1 = c1;

In this example, the expected result of the assignment statement is that i1 will be set to –3. If the implementation defines type char as unsigned, however, sign extension will not occur, and i1 will be 253 (on a two's-complement machine).

Promotion can also occur as a result of a comparison of different types:

char c;

if( c == 0x80 )

.

.

.

This comparison will never evaluate as true on an implementation that sign-extends char types but treats hexadecimal constants as unsigned. Use a character constant of the form '\x80', or explicitly cast the constant to type char to perform the comparison correctly.

The following comparison, which is an example of promotion as a result of a cast, is also nonportable:

char c;

unsigned int u;

if( u == (unsigned)c )

There are two problems with this code:

The char type may be treated as signed or unsigned, depending on the implementation.

If the char type is treated as signed, it can be converted to unsigned in two ways: the char value may first be sign-extended to int, then converted to unsigned; or the char may be converted to unsigned char, then sign-extended to int length.

It is always safe to compare a signed int with a char constant because C requires all character constants to be positive.

Variables of type char are promoted to type int when passed as arguments to a function. This will cause sign extension on some machines. Consider the following code:

char c = 128;

printf( “%d\n”, c );

Microsoft C Specific

Microsoft C allows you to treat type char as signed or unsigned. By default, a char is considered signed, but if you change the default char type using the /J compiler option, you can treat it as unsigned.

Bitwise Right-Shift Operations

Positive or unsigned integral types (char, short, int, and long) yield positive or zero values after a right bitwise shift (>>) operation. For example,

(char)120 >> 4

yields 7,

(unsigned char)240 >> 8

yields 0,

(int)500 >> 8

yields 1, and

(unsigned int)65535 >> 4

yields 4,095.

Negative-signed integral types yield implementation-defined values after a bitwise right-shift operation. This means that you must know whether you want to do a signed or unsigned shift, then code accordingly.

If you don't know how the implementation performs, you may get unexpected results. For example, (signed char)0x80 >> 3 yields 0xf0 if the implementation performs sign extension on right bitwise shifts. If the implementation does not perform the sign extension, the result is 0x10.

You can use right shifts to speed up division when the divisor can be represented by powers of 2 and the dividend is positive. To maintain portability, you should use the division operator.

To perform an unsigned shift, explicitly cast the data to an unsigned type. To perform a shift that extends the sign bit, use the division operator as follows: divide by 2n, where n is the number of bits you want to shift.