この付録では、ISO C の記憶装置におけるデータ表現と、関数に引数を渡す仕組みについて説明します。この付録では、C 言語以外の言語でモジュールを記述したり使用したい場合に、これらのモジュールに C 言語コードとのインタフェースを持たせるための手引きとして書かれたものです。
スタックへの記憶装置の割り当て (内部リンクつまり自動リンクを伴う識別子を使用) は、2G バイト以下に制限すべきです。
使用しているアーキテクチャーによってデータ要素のビット番号の割り当てが異なります。SPARCstationTM ではビット 0 を最下位有効ビット、バイト 0 を最上位有効バイトとしてそれぞれ使用します。次の表に表現方法を示します。
ISO C で使用されている整数型は short、int、long、および 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 モードでは使用できません。
ビット数 |
内容 |
---|---|
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) |
float、double、long double のデータ要素は、ISO IEEE 754-1985 規格に従って次の式のように表現されます。
(-1)s(e- bias)¥2 j.f
ここで
s = 符号
e = バイアス付きの指数
j = 先行ビット。e の値によって決まる。long double (x86) では、先行ビットは明示的。そのほかは暗黙的。
f = 仮数部 (23 ビット)
u = ビットが 0 または 1 を示す。
各ビットの位置は次の表のとおりです。
表 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) |
詳細については、『数値計算ガイド』を参照してください。
正規化された float と double の数は「隠された」ビットまたは暗黙のビットを持つと言われます。それにより、精度を 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)符号n0.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) |
よく使用される数値の 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)
値 |
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 |
詳細については、『数値計算ガイド』を参照してください。
C 言語におけるポインタは 4 バイトを使用します。C でのポインタは、SPARC v9 アーキテクチャーでは 8 バイトを占有します。NULL 値のポインタはゼロと等価です。
配列は、それぞれの要素が決められた記憶順序で格納されます。各要素は実際には記憶要素の一次元の列に格納されます。
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 |
536,870,911 |
288,230,376,151,711,743 |
静的および大域配列にはさらに多くの要素を格納することができます。
この節では、浮動小数点の極値と通常値を組み合わせたものに基本算術演算を適用して得られる結果について説明します。トラップやその他の例外は起こらないものとします。
次の表で、略語の意味を説明します。
表 F–16 略語の使用法
略語 |
意味 |
---|---|
Num |
非正規のまたは正規化された数字 |
Inf |
無限大 (正または負) |
NaN |
数字ではない |
Uno |
順序不定 |
次の表は、異なるタイプのオペランドを組み合わせて行なった算術演算から得られた値のタイプを示しています。
表 F–17 加算と減算の結果表 F–18 乗算結果
|
右側のオペランド: 0 |
右側のオペランド: Num |
右側のオペランド: Inf |
右側のオペランド: NaN |
---|---|---|---|---|
左側のオペランド: 0 |
0 |
0 |
NaN |
NaN |
左側のオペランド: Num |
0 |
Num |
Inf |
NaN |
左側のオペランド: Inf |
NaN |
Inf |
Inf |
NaN |
左側のオペランド: NaN |
NaN |
NaN |
NaN |
NaN |
表 F–19 除算結果
|
右側のオペランド: 0 |
右側のオペランド: Num |
右側のオペランド: Inf |
右側のオペランド: NaN |
---|---|---|---|---|
左側のオペランド: 0 |
NaN |
0 |
0 |
NaN |
左側のオペランド: Num |
Inf |
Num |
0 |
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 と比較結果が等しくなります。
本節では ISO C における引数の渡し方について説明します。
C の関数への引数は、すべて値渡しされます。
実引数は関数の宣言において宣言されるのと逆の順序で渡されます。
実引数が式の場合、関数参照の前に評価されます。その後、式の結果がレジスタに置かれるかスタックにプッシュされます。
関数は 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 は構造体と同様に渡されます。
前述のレジスタは、呼び出し側から見えます。
すべての整数の引数は、8 バイト値として引き渡されます。
浮動小数点引数は可能なかぎり、浮動小数点レジスタに渡されます。
Intel 386 psABI および AMD64 psABI を遵守しています。
関数は次のレジスタで結果を返します。
表 F–21 型を返すために x86 関数が使用するレジスタ
レジスタ |
返される型 |
---|---|
int |
%eax |
%edx と %eax |
|
float、double、long double |
%st(0) |
float _Complex |
%eax (実数部) と %edx (虚数部) |
double _Complex と long double _Complex |
対応する浮動小数点型の 2 つの要素を含む構造体と同じ |
struct、union、long long、double、long double を除くすべての引数は 4 バイト値として渡されます。long long は 8 バイト値として、double は 8 バイト値として、また long double は 12 バイト値としてそれぞれ渡されます。
struct と union はスタックにコピーされます。サイズは 4 の倍数バイトに丸められます。struct と union を返す関数は、その struct や union を格納する場所を指す隠された最初の引数に渡されます。
関数から戻ったあと、スタックから引数をポップするのは呼び出し側の責任です。呼び出された関数によってポップされる struct や union の余分な引数を除きます。