Oracle Solaris Studio 12.2: C ユーザーガイド

7.3.3 符号拡張

型の変換と拡張規則はいくぶん曖昧ですから、64 ビットコンパイル環境への移行で、符号拡張はよく問題になります。符号拡張の問題を避けるには、明示的な型変換を使用して、意図した結果を得られるようにしてください。

符号拡張が発生する理由を理解するには、ISO C の変換規則の知識が役立ちます。32 ビットと 64 ビットコンパイル環境間で最大の符号拡張問題を引き起こすと思われる変換規則は、次の処理で適用されます。

次のコードを 64 ビットプログラムとしてコンパイルすると、addra.base の両方が符号なしの型であっても、addr 変数は符号拡張されます。


%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);
}

ここで符号拡張が起きるのは、次のように変換規則が適用されるためです。


% cc -o test64 -xarch=v9 test.c
% ./test64
addr 0xffffffff80000000
addr 0x80000000
%

同じ例を 32 ビットプログラムとしてコンパイルすると、符号拡張はまったく表示されません。


cc -o test test.c
%test

addr 0x80000000
addr 0x80000000

変換規則の詳細については、ANSI/ISO C 規格の仕様書を参照してください。この規格には通常の演算変換や整数定数に関する有用な規則も規定されています。