Sun Studio 12: C ユーザーズガイド

付録 F ISO C データ表現

この付録では、ISO C の記憶装置におけるデータ表現と、関数に引数を渡す仕組みについて説明します。この付録では、C 言語以外の言語でモジュールを記述したり使用したい場合に、これらのモジュールに C 言語コードとのインタフェースを持たせるための手引きとして書かれたものです。

F.1 記憶装置の割り当て

データ型とその表現方法について次の表にまとめます。


注 –

スタックへの記憶装置の割り当て (内部リンクつまり自動リンクを伴う識別子を使用) は、2G バイト以下に制限すべきです。


表 F–1 データ型に対する記憶装置の割り当て

データ型 

内部表現 

char 型要素

8 ビット幅のシングルバイト。1 バイトで境界整列される。 

short 型整数

ハーフワード (2 バイト、つまり 16 ビット)。2 バイトで境界整列される。 

int

32 ビット (4 バイトまたは 1 ワード)、4 バイト境界で整列される。 

long

v8 および x86 では 32 ビット (4 バイトまたは 1 ワード)、4 バイト境界で整列される。 

v9 では 64 ビット (8 バイトまたは 2 ワード)、8 バイト境界で整列される。 

pointer

v8 および x86 では 32 ビット (4 バイトまたは 1 ワード)、4 バイト境界で整列される。 

v9 では 64 ビット (8 バイトまたは 2 ワード)、8 バイト境界で整列される。 

long long [long long は、-Xc モードで -xc99=none を指定した場合は利用できません。]

(SPARC) 64 ビット (8 バイト、つまり 2 ワード)。8 バイト境界で整列される。 

(x86) 64 ビット (8 バイト、つまり 2 ワード)。4 バイト境界で整列される。

float

32 ビット (4 バイト、つまり 1 ワード)。4 バイトで境界整列される。1 ビットの符号、8 ビットの指数部および 23 ビットの仮数部から成る。 

double

64 ビット (8 バイト、つまり 2 ワード)。8 バイトで境界整列される (SPARC) 。または、4 バイト境界に割り当てられる (x86)。1 ビットの符号、11 ビットの指数部、52 ビットの仮数部から成る。

long double

v8 (SPARC) 128 ビット (16 バイト、つまり 4 ワード)。8 バイトで境界整列される。1 ビットの符号、15 ビットの指数部および 112 ビットの仮数部から成る。 

v9 (SPARC) 128 ビット (16 バイト、つまり 4 ワード)。16 バイトで境界整列される。1 ビットの符号、15 ビットの指数部および 112 ビットの仮数部から成る。 

(x86) 96 ビット (12 バイト、つまり 3 ワード)。4 バイトで境界整列される。1 ビットの符号、16 ビットの指数部および 64 ビットの仮数部から成る。16 ビットは使用されない。

F.2 データ表現

使用しているアーキテクチャーによってデータ要素のビット番号の割り当てが異なります。SPARCstationTM ではビット 0 を最下位有効ビット、バイト 0 を最上位有効バイトとしてそれぞれ使用します。次の表に表現方法を示します。

F.2.1 整数表現

ISO C で使用されている整数型は shortintlong、および long long です。

表 F–2 short の表現

ビット数 

内容 

8- 15 

バイト 0 (SPARC) 

バイト 1 (x86)

0- 7 

バイト 1 (SPARC) 

バイト 0 (x86) 

表 F–3 int の表現

ビット数 

内容 

24- 31 

バイト 0 (SPARC) 

バイト 3 (x86) 

16- 23 

バイト 1 (SPARC) 

バイト 2 (x86) 

8- 15 

バイト 2 (SPARC) 

バイト 1 (x86) 

0- 7 

バイト 3 (SPARC) 

バイト 0 (x86) 

表 F–4 long の表現 (x86、SPARC v8、SPARC v9)

ビット数 

内容 

24- 31 

バイト 0 (SPARC) v8 

バイト 4 (SPARC) v9 

バイト 3 (x86) 

16- 23 

バイト 1 (SPARC) v8 

バイト 5 (SPARC) v9 

バイト 2 (x86)

8- 15 

バイト 2 (SPARC) v8 

バイト 6 (SPARC) v9 

バイト 1 (x86)

0- 7 

バイト 3 (SPARC) v8 

バイト 7 (SPARC) v9 

バイト 0 (x86)


注 –

long long-Xc モードでは使用できません。


表 F–5 long long の表現

ビット数 

内容 

56- 63 

バイト 0 (SPARC) 

バイト 7 (x86) 

48- 55 

バイト 1 (SPARC) 

バイト 6 (x86) 

40- 47 

バイト 2 (SPARC) 

バイト 5 (x86) 

32- 39 

バイト 3 (SPARC) 

バイト 4 (x86) 

24- 31 

バイト 4 (SPARC) 

バイト 3 (x86) 

16- 23 

バイト 5 (SPARC) 

バイト 2 (x86) 

8- 15 

バイト 6 (SPARC) 

バイト 1 (x86) 

0- 7 

バイト 7 (SPARC) 

バイト 0 (x86) 

F.2.2 浮動小数点表現

floatdoublelong double のデータ要素は、ISO IEEE 754-1985 規格に従って次の式のように表現されます。

(-1)s(e- bias)¥2 j.f

ここで

各ビットの位置は次の表のとおりです。

表 F–6 float の表現

ビット数 

名 

31 

符号 (Sign) 

23- 30 

指数部 (Exponent) 

0- 22 

仮数部 (Fraction) 

表 F–7 double の表現

ビット数 

名 

63 

符号 (Sign) 

52- 62 

指数部 (Exponent) 

0- 51 

仮数部 (Fraction) 

表 F–8 long double の表現 (SPARC)

ビット数 

名 

127 

符号 (Sign) 

112- 126 

指数部 (Exponent) 

0- 111 

仮数部 (Fraction) 

表 F–9 long double の表現 (x86)

ビット数 

名 

80- 95 

使用せず 

79 

符号 (Sign) 

64- 78 

指数部 (Exponent) 

63 

先行ビット 

0- 62 

仮数部 (Fraction) 

詳細については、『数値計算ガイド』を参照してください。

F.2.3 極値表現

正規化された floatdouble の数は「隠された」ビットまたは暗黙のビットを持つと言われます。それにより、精度を 1 ビット分高めることができます。long double の場合は、先行ビットは暗黙的 (SPARC) または明示的 (x86) のいずれかになります。このビットは正規数に対しては 1、非正規数に対しては 0 になります。

表 F–10 float の表現

正規数 (0<e<255): 

(-1)符号2 (指数部- 127)1.f

非正規数 

(e=0, f!=0): 

(-1)符号2 (-126)0.f

ゼロ (e=0, f=0): 

(-1)符号0.0

シグナルを発生する NaN 

s=u, e=255(最大値); f=.0uuu〜uu (少なくとも 1 ビットは 0 以外) 

シグナルを発生しない NaN 

s=u, e=255(最大値); f=.1uuu〜uu 

無限大 

s=u, e=255(最大値); f=.0000〜00 (すべてが 0) 

表 F–11 double の表現

正規数 (0<e<2047): 

(-1)符号2 (指数部 - 1023)1.f

非正規数 (e=0, f!=0): 

(-1)符号2 (-1022)0.f

ゼロ (e=0, f=0): 

(-1)符号0.0

シグナルを発生する NaN 

s=u, e=2047(最大値); f=.0uuu〜uu (少なくとも 1 ビットは 0 以外) 

シグナルを発生しない NaN 

s=u, e=2047(最大値); f=.1uuu〜uu 

無限大 

s=u, e=2047(最大値); f=.0000〜00 (すべてが 0) 

表 F–12 long double の表現

正規数 (0<e<32767): 

(-1)符号2 (指数部 - 16383)1.f

非正規数 (e=0, f!=0): 

(-1)符号2 (-16382)0.f

ゼロ (e=0, f=0): 

(-1)符号0.0

シグナルを発生する NaN 

s=u, e=32767(符号); f=.0uuu〜uu (少なくとも 1 ビットは 0 以外) 

シグナルを発生しない NaN 

s=u, e=32767(最大値); f=.1uuu〜uu 

無限大 

s=u, e=32767(最大値); f=.0000〜00 (すべてが 0) 

F.2.4 重要な数の 16 進数表現

よく使用される数値の 16 進数表現を次の表にまとめます。

表 F–13 重要な数の 16 進数表現 (SPARC)

値 

float

double

long double

+0 

-0 

00000000 

80000000 

0000000000000000 

8000000000000000 

00000000000000000000000000000000 

80000000000000000000000000000000 

+1.0 

-1.0 

3F800000 

BF800000 

3FF0000000000000 

BFF0000000000000 

3FFF00000000000000000000000000000 

BFFF00000000000000000000000000000 

+2.0 

+3.0 

40000000 

40400000 

4000000000000000 

4008000000000000 

40000000000000000000000000000000 

40080000000000000000000000000000 

プラス無限大 

マイナス無限 

7F800000 

FF800000 

7FF0000000000000 

FFF0000000000000 

7FFF00000000000000000000000000000 

FFFF00000000000000000000000000000 

NaN 

7FBFFFFF 

7FF7FFFFFFFFFFFF 

7FFF7FFFFFFFFFFFFFFFFFFFFFFFFFFF 

表 F–14 重要な数の 16 進数表現 (x86)

Value  

float

double

long double

+0 

-0 

00000000 

80000000 

0000000000000000 

0000000080000000 

00000000000000000000 

80000000000000000000 

+1.0 

-1.0 

3F800000 

BF800000 

000000003FF00000 

00000000BFF00000 

3FFF8000000000000000 

BFFF8000000000000000 

+2.0 

+3.0 

40000000 

40400000 

0000000040000000 

0000000040080000 

40008000000000000000 

4000C000000000000000 

プラス無限大 

マイナス無限 

7F800000 

FF800000 

000000007FF00000 

00000000FFF00000 

7FFF8000000000000000 

FFFF8000000000000000 

NaN 

7FBFFFFF 

FFFFFFFF7FF7FFFF 

7FFFBFFFFFFFFFFFFFFF 

詳細については、『数値計算ガイド』を参照してください。

F.2.5 ポインタ表現

C 言語におけるポインタは 4 バイトを使用します。C でのポインタは、SPARC v9 アーキテクチャーでは 8 バイトを占有します。NULL 値のポインタはゼロと等価です。

F.2.6 配列の格納

配列は、それぞれの要素が決められた記憶順序で格納されます。各要素は実際には記憶要素の一次元の列に格納されます。

C 言語の配列は行の並びを優先して格納されます。この順序では、多次元配列における右端の添字がもっとも速く変化します。

文字列データ型は char 要素の配列になります。連結後、文字列リテラルまたはワイド文字列リテラルに指定できる最大の文字数は、4,294,967,295 個です。

スタックに割り当てられた記憶領域のサイズ制限については、「F.1 記憶装置の割り当て」を参照してください。

表 F–15 配列の型と最大の大きさ

型 

SPARC および x86 の最大要素数 

SPARC V9 の最大要素数 

char

4,294,967,295 

2,305,843,009,213,693,951 

short

2,147,483,647 

1,152,921,504,606,846,975 

int

1,073,741,823 

576,460,752,303,423,487 

long

1,073,741,823 

288,230,376,151,711,743 

float

1,073,741,823 

576,460,752,303,423,487 

double

536,870,911 

288,230,376,151,711,743 

long double

268,435,451 

144,115,188,075,855,871 

long long [-Xc モードで -xc99=none を指定した場合は無効です。]

536,870,911 

288,230,376,151,711,743 

静的および大域配列にはさらに多くの要素を格納することができます。

F.2.7 極値の算術演算

この節では、浮動小数点の極値と通常値を組み合わせたものに基本算術演算を適用して得られる結果について説明します。トラップやその他の例外は起こらないものとします。

次の表で、略語の意味を説明します。

表 F–16 略語の使用法

略語 

意味 

Num 

非正規のまたは正規化された数字 

Inf 

無限大 (正または負) 

NaN 

数字ではない 

Uno 

順序不定 

次の表は、異なるタイプのオペランドを組み合わせて行なった算術演算から得られた値のタイプを示しています。

表 F–17 加算と減算の結果

 

右側のオペランド: 0 

右側のオペランド: Num 

右側のオペランド: Inf 

右側のオペランド: NaN 

左側のオペランド: 0 

Num 

Inf 

NaN 

左側のオペランド: Num 

Num 

を参照してください。 [Num + Num は、結果が大きすぎる (オーバーフロー) 場合は Num ではなく Inf になることがあります。無限量が逆の sign の場合は、Inf + Inf = NaN になります。]

Inf 

NaN 

左側のオペランド: Inf 

Inf 

Inf 

を参照してください。

NaN 

左側のオペランド: NaN 

NaN 

NaN 

NaN 

NaN 

表 F–18 乗算結果

 

右側のオペランド:0 

右側のオペランド:Num 

右側のオペランド:Inf 

右側のオペランド:NaN 

左側のオペランド:0 

NaN 

NaN 

左側のオペランド: Num 

Num 

Inf 

NaN 

左側のオペランド: Inf 

NaN 

Inf 

Inf 

NaN 

左側のオペランド: NaN 

NaN 

NaN 

NaN 

NaN 

表 F–19 除算結果

 

右側のオペランド:0 

右側のオペランド:Num 

右側のオペランド:Inf 

右側のオペランド:NaN 

左側のオペランド:0 

NaN 

NaN 

左側のオペランド: Num 

Inf 

Num 

NaN 

左側のオペランド: Inf 

Inf 

Inf 

NaN 

NaN 

左側のオペランド: NaN 

NaN 

NaN 

NaN 

NaN 

表 F–20 比較結果

 

右側のオペランド:0 

右側のオペランド:+Num 

右側のオペランド:+Inf 

右側のオペランド:+NaN 

左側のオペランド:0 

Uno 

左側のオペランド: +Num 

比較の結果 

Uno 

左側のオペランド: +Inf 

Uno 

左側のオペランド: +NaN 

Uno 

Uno 

Uno 

Uno 


注 –

NaN と比較した NaN は順序不定で、結果は不等価になります。+0 は -0 と比較結果が等しくなります。


F.3 引数を渡す仕組み

本節では ISO C における引数の渡し方について説明します。

F.3.1 32 ビット SPARC

関数は integer 型の結果をレジスタ %o0 に返します。float 型の結果はレジスタ %f0 に、double 型の結果はレジスタ %f0%f1 に返します。

long long 型 整数は上位ワードは %oN 下位ワードは %o(N+1) というようにレジスタに渡されます。 レジスタ内の結果は同様の順序で %o0%o1 に返されます。

double および long double 型を除くすべての引数は 4 バイトの値として渡されます。double 型は 8 バイトの値として渡されます。先頭 6 個の 4 バイト値 (double を 8 と数える) は %o0 から %o5 までのレジスタに渡され、残りはスタック経由で渡されます。構造体の場合は、構造体のコピーが作成され、ポインタがそのコピーに渡されます。long double は構造体と同様に渡されます。

前述のレジスタは、呼び出し側から見えます。

F.3.1.1 64 ビット SPARC

すべての整数の引数は、8 バイト値として引き渡されます。

浮動小数点引数は可能なかぎり、浮動小数点レジスタに渡されます。

(x86)

関数は次のレジスタで結果を返します。

表 F–21 型を返すために x86 関数が使用するレジスタ

レジスタ 

返される型 

int 

%eax 

long long

%edx%eax

floatdoublelong double

%st(0)

float _Complex

%eax (実数部) と %edx (虚数部)

double _Complexlong double _Complex

対応する浮動小数点型の 2 つの要素を含む構造体と同じ 

structunionlong longdoublelong double を除くすべての引数は 4 バイト値として渡されます。 long long は 8 バイト値として、double は 8 バイト値として、また long double は 12 バイト値としてそれぞれ渡されます。

structunion はスタックにコピーされます。サイズは 4 の倍数バイトに丸められます。structunion を返す関数は、その structunion を格納する場所を指す隠された最初の引数に渡されます。

関数から戻ったあと、スタックから引数をポップするのは呼び出し側の責任です。呼び出された関数によってポップされる structunion の余分な引数を除きます。