Sign extension is a common problem when you convert to the 64-bit compilation environment because the type conversion and promotion rules are somewhat obscure. To prevent sign extension problems, use explicit casting to achieve the intended results.To understand why sign extension occurs, it helps to understand the conversion rules for ANSI/ISO C. The conversion rules that seem to cause the most sign extension problems between the 32-bit and the 64-bit compilation environment come into effect during the following operations:
Integral promotion
If an integer can hold all possible values of the original type, the value is converted to an integer; otherwise, the value is converted to an unsigned integer.
Conversion between signed and unsigned integers
%cat test.c struct foo { unsigned int base:19, rehash:13; }; main(int argc, char *argv[]) { struct foo a; unsigned long addr; a.base = 0x40000; addr = a.base << 13; /* Sign extension here! */ printf("addr 0x%lx\n", addr); addr = (unsigned int)(a.base << 13); /* No sign extension here! */ printf("addr 0x%lx\n", addr); }
This sign extension occurs because the conversion rules are applied as follows:
a.base is converted from an unsigned int to an int because of the integral promotion rule. Thus, the expression a.base << 13 is of type int, but no sign extension has yet occurred.
The expression a.base << 13 is of type int, but it is converted to a long and then to an unsigned long before being assigned to addr, because of signed and unsigned integer promotion rules. The sign extension occurs when it is converted from an int to a long.
% cc -o test64 -xarch=v9 test.c % ./test64 addr 0xffffffff80000000 addr 0x80000000 %
When this same example is compiled as a 32-bit program it does not display any sign extension:
int *end; int *p; p = malloc(4 * NUM_ELEMENTS); end = (int *)((unsigned int)p + 4 * NUM_ELEMENTS); % warning: conversion of pointer loses bits
For a more detailed discussion of the conversion rules, refer to the ANSI/ISO C standard. Also included in this standard are useful rules for ordinary arithmetic conversions and integer constants.