この付録では、ISO C の記憶装置におけるデータ表現と、関数に引数を渡す仕組みについて説明します。この付録では、C 言語以外の言語でモジュールを記述したり使用したい場合に、これらのモジュールに C 言語コードとのインタフェースを持たせるための手引きとして書かれたものです。
スタックへの記憶装置の割り当て (内部リンクつまり自動リンクを伴う識別子を使用) は、2G バイト以下に制限すべきです。
| C の型 | LP64 (-m64) サイズ | LP64 整列 | ILP32 (-m32) サイズ | ILP 32 整列 | 
|---|---|---|---|---|
| Integral | ||||
| _Bool char signed char unsigned char | 1 | 1 | 1 | 1 | 
| short signed short unsigned short | 2 | 2 | 2 | 2 | 
| int signed int unsigned int enum | 4 | 4 | 4 | 4 | 
| long signed long unsigned long | 8 | 8 | 4 | 4 | 
| long long signed long long unsigned long long | 8 | 8 | 8 | 4 (x86) / 8 (SPARC) | 
| Pointer | ||||
| 任意の型 * 任意の型 (*) () | 8 | 8 | 4 | 4 | 
| Floating Point | ||||
| float double long double | 4 8 16 | 4 8 16 | 4 8 12 (x86) / 16 (SPARC) | 4 4 (x86) / 8 (SPARC) 4 (x86) / 8 (SPARC) | 
| Complex | ||||
| float _Complex double _Complex long double _Complex | 8 16 32 | 4 8 16 | 8 16 24 (x86) / 32 (SPARC) | 4 4 (x86) / 8 (SPARC) 4 (x86) / 16 (SPARC) | 
| Imaginary | ||||
| float _Imaginary double _Imaginary long double _Imaginary | 4 8 16 | 4 8 16 | 4 8 12 (x86) / 16 (SPARC) | 4 4 (x86) / 8 (SPARC) 4 (x86) / 16 (SPARC) | 
使用しているアーキテクチャーによってデータ要素のビット番号の割り当てが異なります。SPARCstation ではビット 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 の表現と -m32 でのコンパイル
| ビット数 | 内容 | 
|---|---|
| 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–5 long (-m64) および long long (-m32 と -m64 の両方) の表現
| ビット数 | 内容 | 
|---|---|
| 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 *2(e - bias) *[j.f]
ここで
s = 符号
e = バイアス付きの指数
j = 先行ビット。e の値によって決まる。long double (x86) では、先行ビットは明示的。そのほかは暗黙的。
f = 仮数部 (23 ビット)
u は、ビットが 0 でも 1 でも良いことを意味します (次の表で使用)。
IEEE Single および Double の場合、j は常に暗黙的です。バイアス付きの指数が 0 の場合、f が 0 でない限り、j は 0 で、結果として生成される数値は非正規数です。バイアス付きの指数が 0 より大きい場合、数値が有限である限り j は 1 です。
Intel 80 ビット拡張の場合、j は常に明示的です。
各ビットの位置は次の表のとおりです。
表 F–6 float の表現| ビット数 | 名 | 
|---|---|
| 31 | 符号 | 
| 23- 30 | バイアス付きの指数 | 
| 0- 22 | 仮数部 | 
表 F–7 double の表現
| ビット数 | 名 | 
|---|---|
| 63 | 符号 | 
| 52- 62 | バイアス付きの指数 | 
| 0- 51 | 仮数部 | 
表 F–8 long double の表現 (SPARC)
| ビット数 | 名 | 
|---|---|
| 127 | 符号 | 
| 112- 126 | バイアス付きの指数 | 
| 0- 111 | 仮数部 | 
表 F–9 long double の表現 (x86)
| ビット数 | 名 | 
|---|---|
| 80- 95 | 使用されない | 
| 79 | 符号 | 
| 64- 78 | バイアス付きの指数 | 
| 63 | 先行ビット | 
| 0- 62 | 仮数部 | 
詳細については、『数値計算ガイド』を参照してください。
正規化された float と double の数は「隠された」ビットまたは暗黙のビットを持つと言われます。それにより、精度を 1 ビット分高めることができます。long double の場合は、先行ビットは暗黙的 (SPARC) または明示的 (x86) のいずれかになります。このビットは正規数に対しては 1、非正規数に対しては 0 になります。
表 F–10 float の表現| 正規数 (0<e<255): | (-1)s2 (e-127)1. f | 
| 非正規数 (e=0, f!=0): | (-1)s2 (-126)0. f | 
| ゼロ (e=0, f=0): | (-1)s0.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)s2 (e-1023)1. f | 
| 非正規数 (e=0, f!=0): | (-1)s2 (-1022)0. f | 
| ゼロ (e=0, f=0): | (-1)s0.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)s2 (e- 16383)1.f | 
| 非正規数 (e=0, f!=0): | (-1)s2 (-16382)0. f | 
| ゼロ (e=0, f=0): | (-1)s0.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 配列の型と最大の大きさ| 種類 | -m32 の要素の最大数 | -m64 の要素の最大数 | 
|---|---|---|
| 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 | 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 つの要素を含む構造体と同じ | 
詳細は、http://www.x86-64.org/documentation/abi.pdfで AMD64 psABI についての説明を参照してください。
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 の余分な引数を除きます。