ISO C データ表現
この付録では、ISO C の記憶装置におけるデータ表現と、関数に引数を渡す仕組みについて説明します。C 言語以外の言語でモジュールを記述したり使用したいプログラマが、それらのモジュールに C 言語コードとのインタフェースを持たせるための手引きとして役立つかもしれません。
G.1 記憶領域の割り当て
データ型とその表現方法について次の表にまとめます。サイズはバイト単位です。
注 - スタックへの記憶装置の割り当て (内部リンクつまり自動リンクを伴う識別子を使用) は、2G バイト以下に制限すべきです。
表 G-1 データ型の記憶装置の割り当て | | | | |
整数
|
_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)
|
ポインタ
|
任意の型 * 任意の型 (*) ()
| 8
| 8
| 4
| 4
|
浮動小数点
|
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)
|
複素数
|
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)
|
虚数
|
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)
|
|
G.2 データ表現
与えられたデータ要素のビット番号の割り当ては、使用しているアーキテクチャーによって異なります。SPARCstation マシンではビット 0 を最下位有効ビット、バイト 0 を最上位有効バイトとしてそれぞれ使用します。次の表に表現方法を示します。
G.2.1 整数表現
ISO C で使用されている整数型は short、int、long、および long long です。
表 G-2 short の表現 | |
8- 15
| バイト 0 (SPARC) バイト 1 (x86)
|
0- 7
| バイト 1 (SPARC) バイト 0 (x86)
|
|
表 G-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)
|
|
表 G-4 -m32 でコンパイルされる long の表現 | |
24- 31
| バイト 0 (SPARC) バイト 3 (x86)
|
16- 23
| バイト 1 (SPARC) バイト 2 (x86)
|
8- 15
| バイト 2 (SPARC) バイト 1 (x86)
|
0- 7
| バイト 3 (SPARC) バイト 0 (x86)
|
|
表 G-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)
|
|
G.2.2 浮動小数点表現
float、double、long double のデータ要素は、ISO IEEE 754-1985 規格に従って表現されます。表現は次のとおりです。
(-1)s *2(e - bias) *[j.f]
ここでは:
IEEE Single および Double の場合、j は常に暗黙的です。バイアス付きの指数が 0 の場合、f が 0 でない限り、j は 0 で、結果として生成される数値は非正規数です。バイアス付きの指数が 0 より大きい場合、数値が有限である限り j は 1 です。
Intel 80 ビット拡張の場合、j は常に明示的です。
各ビットの位置は次の表のとおりです。
表 G-6 float の表現 | |
31
| 符号
|
23- 30
| バイアス付きの指数
|
0- 22
| 仮数部
|
|
表 G-7 double の表現 | |
63
| 符号
|
52- 62
| バイアス付きの指数
|
0- 51
| 仮数部
|
|
表 G-8 long double の表現 (SPARC) | |
127
| 符号
|
112- 126
| バイアス付きの指数
|
0- 111
| 仮数部
|
|
表 G-9 long double の表現 (x86) | |
80- 95
| 使用されない
|
79
| 符号
|
64- 78
| バイアス付きの指数
|
63
| 先行ビット
|
0- 62
| 仮数部
|
|
詳細については、『数値計算ガイド』を参照してください。
G.2.3 極値
正規化された float と double の数は「隠された」ビットまたは暗黙のビットを持つと言われます。それにより、精度を 1 ビット分高めることができます。long double の場合は、先行ビットは暗黙的 (SPARC) または明示的 (x86) のいずれかになります。このビットは正規数に対しては 1、非正規数に対しては 0 になります。
表 G-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)
|
|
表 G-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)
|
|
表 G-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)
|
|
G.2.4 重要な数の 16 進数表現
よく使用される数値の 16 進数表現を次の表にまとめます。
表 G-13 重要な数の 16 進数表現 (SPARC) | | | |
+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
|
|
表 G-14 重要な数の 16 進数表現 (x86) | | | |
+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
|
|
詳細については、『数値計算ガイド』を参照してください。
G.2.5 ポインタ表現
C 言語におけるポインタは 4 バイトを使用します。C のポインタは、64 ビット SPARC v9 アーキテクチャーでは 8 バイトを占有します。NULL 値のポインタはゼロと等価です。
G.2.6 配列の格納
配列は、それぞれの要素が決められた記憶順序で格納されます。各要素は実際には記憶要素の一次元の列に格納されます。
C の配列は行メジャー順で格納されます。多次元配列の最後の添字はもっとも速く変化します。
文字列データ型は char 要素の配列です。連結後、文字列リテラルまたはワイド文字列リテラルに指定できる最大の文字数は、4,294,967,295 個です。
スタックに割り当てられた記憶領域のサイズ制限については、記憶領域の割り当てを参照してください。
表 G-15 配列の型と最大の大きさ | | |
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
|
|
静的および大域配列にはさらに多くの要素を格納することができます。
G.2.7 極値の算術演算
このセクションでは、浮動小数点の極値と通常値を組み合わせたものに基本算術演算を適用して得られる結果について説明します。トラップやその他の例外は起こらないものとします。
次の表で、略語を説明します。
表 G-16 略語の使用法
|
|
Num
|
非正規のまたは正規化された数字
|
Inf
|
無限大 (正または負)
|
NaN
|
数字ではない
|
Uno
|
順序不定
|
|
次の表は、異なるタイプのオペランドを組み合わせて行なった算術演算から得られた値のタイプを示しています。
表 G-17 加算と減算の結果 | | | | |
左側のオペランド: 0
| 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
|
|
表 G-18 乗算結果 | | | | |
左側のオペランド: 0
| 0
| 0
| NaN
| NaN
|
左側のオペランド: Num
| 0
| Num
| Inf
| NaN
|
左側のオペランド: Inf
| NaN
| Inf
| Inf
| NaN
|
左側のオペランド: NaN
| NaN
| NaN
| NaN
| NaN
|
|
表 G-19 除算結果 | | | | |
左側のオペランド: 0
| NaN
| 0
| 0
| NaN
|
左側のオペランド: Num
| Inf
| Num
| 0
| NaN
|
左側のオペランド: Inf
| Inf
| Inf
| NaN
| NaN
|
左側のオペランド: NaN
| NaN
| NaN
| NaN
| NaN
|
|
表 G-20 比較結果 | | | | |
左側のオペランド: 0
| =
| <
| <
| Uno
|
左側のオペランド: +Num
| >
| 比較の結果
| <
| Uno
|
左側のオペランド: +Inf
| >
| >
| =
| Uno
|
左側のオペランド: +NaN
| Uno
| Uno
| Uno
| Uno
|
|
注 - NaN と比較した NaN は順序不定で、結果は不等価になります。+0 は -0 と比較結果が等しくなります。
G.3 引数を渡す仕組み
本セクションでは ISO C における引数の渡し方について説明します。
G.3.1 32 ビット SPARC
関数は integer 型の結果をレジスタ %o0 に、float 型の結果wpレジスタ %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 は構造体と同様の方法で渡されます。
前述のレジスタは、呼び出し側から見えます。
G.3.2 64 ビット SPARC
すべての整数の引数は、8 バイト値として引き渡されます。
浮動小数点引数は可能なかぎり、浮動小数点レジスタに渡されます。
G.3.3 x86/x64
Intel 386 psABI および AMD64 psABI を遵守しています。
関数は次のレジスタで結果を返します。
表 G-21 型を返すために x86 関数が使用するレジスタ (-m32)
|
|
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.pdfhttp://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 の余分な引数を除き、スタックから引数をポップするのは呼び出し側の責任です。