本附录描述 ISO C 如何表示存储器中的数据以及向函数传递参数的机制。其目的是为想要编写或使用非 C 语言模块并将这些模块与 C 代码连接的程序员提供指导。
栈中分配的存储空间(带有内部、自动或链接的标识符)应限于 2G 字节或更少。
C 类型 |
LP64 (-m64) 大小 |
LP64 对齐 |
ILP32 (-m32) 大小 |
ILP 32 对齐 |
---|---|---|---|---|
整数 |
||||
_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) |
指针 |
||||
any-type * any-type (*) () |
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) |
任何给定数据元素的位编号取决于使用的体系结构: SPARC 工作站机器将位 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 = sign
e = 偏置指数
j 为前导位,由 e 的值确定。在 long double (x86) 情况下,前导位是显式的;在所有其他情况下,它是隐式的。
f = 尾数
u 表示位可以是 1 或 0(在下列表格中使用)。
对于 IEEE Single 和 Double,j 总是隐式的。偏置指数为 0 时, j 为 0,只要 f 不为 0,生成的数字就不太正常。偏置指数大于 0 时,只要该数字是有限的,j 就为 1。
对于 Intel 80 位 Extended,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 数被认为包含一个“隐藏的”或隐含的位,从而比不包含该位时的精度高一位。对于 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(max);f=.0uuu-uu;至少一个位必须为非零 |
静态 NaN |
s=u,e=255(max);f=.1uuu-uu |
无穷 |
s=u,e=255(max);f=.0000-00(全为零) |
表 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(max);f=.0uuu-uu;至少一个位必须为非零 |
静态 NaN |
s=u,e=2047(max);f=.1uuu-uu |
无穷 |
s=u,e=2047(max);f=.0000-00(全为零) |
表 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(max);f=.0uuu-uu;至少一个位必须为非零 |
静态 NaN |
s=u,e=32767(max);f=.1uuu-uu |
无穷 |
s=u,e=32767(max);f=.0000-00(全为零) |
下表显示十六进制表示。
表 F–13 选定数的十六进制表示法 (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 选定数的十六进制表示法 (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 函数的所有参数均通过值进行传递。
实际参数按函数声明中声明参数的反向顺序传递。
本身为表达式的实际参数在函数引用之前求值。然后表达式的结果置入寄存器或推入栈。
函数在寄存器 %o0 中返回 integer 结果,在寄存器 %f0 中返回 float 结果,在寄存器 %f0 和 %f1 中返回 double 结果。
long long 整数以较高词序在 %oN 寄存器中进行传递,以较低词序在 %o(N+1) 寄存器中进行传递。寄存器中的结果在 %o0 和 %o1 中返回,排序相似。
除 doubles 和 long double 外,所有参数都作为四字节值来传递。double 作为八字节值传递。前六个四字节值(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 |
与包含相应浮点类型的两个元素的结构相同。 |
有关详细信息,请参阅 http://www.x86-64.org/documentation/abi.pdf 上的 AMD64 psABI
除了 struct、union、long long、double 和 long double 之外的所有参数都作为四字节值传递;long long 作为八字节值传递,double 作为八字节值传递,long double 作为 12 字节值传递。
struct 和 union 被复制到栈中。大小向上舍入为 4 字节的倍数。返回 struct 和 union 的函数被传递一个隐藏的首参数,并指向返回的 struct 或 union 的存储位置。
从一个函数返回时,需要调用程序从栈中弹出参数,但 struct 和 union 返回的附加参数除外,它由调用的函数弹出。