Solaris(64 位)开发者指南

实现单一源代码

以下几节介绍了一些可供应用程序开发者使用的资源,可帮助编写能够同时支持 32 位编译和 64 位编译的单一源代码。

系统头文件 <sys/types.h><inttypes.h> 中包含有助于使应用程序对于 32 位和 64 位均安全的常量、宏和派生类型。尽管详细讨论这些内容超出了本文档的范围,但是以下各节以及附录 A,派生类型更改 中仍讨论了其中的部分内容。

功能测试宏

包含 <sys/types.h> 的应用程序源文件可以通过包括 <sys/isa_defs.h> 使编程模型符号 _LP64_ILP32 的定义可用。

有关预处理程序符号(_LP64_ILP32)和宏(_LITTLE_ENDIAN_BIG_ENDIAN6)的信息,请参见 types(3HEAD)。

派生类型

使用系统派生类型有助于使代码对于 32 位和 64 位均安全,这是由于派生类型本身对于 ILP32 和 LP64 数据模型均安全。通常,使用派生类型以便于更改是良好的编程做法。如果数据模型在将来发生变化,或者在移植到其他平台时,只需更改系统派生类型即可,而无需更改应用程序。

<sys/types.h> 文件

<sys/types.h> 头文件中包含大量应在适当时机使用的基本派生类型。特别是以下几种类型颇受关注:

clock_t

类型 clock_t 表示系统时间(以时钟周期为单位)。

dev_t

类型 dev_t 用于设备号。

off_t

类型 off_t 用于文件大小和偏移量。

ptrdiff_t

类型 ptrdiff_t 是一种带符号整数类型,用于对两个指针执行减法运算后所得的结果。

size_t

类型 size_t 用于内存中对象的大小(以字节为单位)。

ssize_t

带符号的大小类型 ssize_t 供返回字节计数或错误指示的函数使用。

time_t

类型 time_t 用于时间(以秒为单位)。

所有这些类型在 ILP32 编译环境中都保持 32 位值,并会在 LP64 编译环境中增加到 64 位值。

其中某些类型的用法将在本章转换为 LP64 的指导原则中更详细地介绍。

<inttypes.h> 文件

在 Solaris 2.6 发行版中添加了头文件 <inttypes.h>,程序员可利用它提供的常量、宏和派生类型使其代码与显式指定大小的数据项兼容,而不管编译环境如何。该文件中包含用来处理 8 位、16 位、32 位和 64 位对象的机制,它是 ANSI C 议案的一部分,可以与 ISO/JTC1/SC22/WG14 C 委员会对当前 ISO C 标准(即 ISO/IEC 9899:1990 编程语言-C)所进行修订的工作草案保持一致。

<inttypes.h> 提供的基本功能包括:

以下各节中将对这些功能进行更详细的讨论。

定宽的整数类型

<inttypes.h> 提供的定宽整数类型同时包括带符号整数类型(如 int8_tint16_tint32_tint64_t)以及无符号整数类型(如 uint8_tuint16_tuint32_tuint64_t)。定义为可具有指定位数的最短整数类型的派生类型包括 int_least8_tint_least64_tuint_least8_tuint_least64_t

不应不加选择地使用这些定宽类型。例如,类型 int 可以继续用于循环计数器和文件描述符,类型 long 可用于数组索引。另一方面,对于以下各项的显式二进制表示形式,则应使用定宽类型:

uintptr_t 和其他有用的类型

<inttypes.h> 提供的其他有用类型包括大小足以包含一个指针的带符号整数类型和无符号整数类型。这些类型以 intptr_tuintptr_t 形式提供。此外,还会将 intmax_tuintmax_t 分别定义为可用的最长(以位为单位)带符号整数类型和无符号整数类型。

选用 uintptr_t 类型作为指针的整数类型比使用基本类型(如 unsigned long)要好。尽管在 ILP32 和 LP64 数据模型中,类型 unsigned long 与指针的长度相同,但如果使用 uintptr_t,则只需在使用其他数据模型时更改 uintptr_t 的定义即可。这会使其可移植到许多其他系统中,并且还可以在 C 中更为清楚地表达意图。

需要执行地址运算时,intptr_tuintptr_t 类型对于强制转换指针非常有用。因此,应使用这些类型,而不是使用 longunsigned long 类型。


注 –

使用 uintptr_t 进行强制类型转换通常比使用 intptr_t 安全,在进行比较时尤为安全。


常量宏

提供宏的目的在于指定给定常量的大小和符号。这些宏包括 INT8_C(c)INT64_C(c)UINT8_C(c)UINT64_C(c) 等。基本上,这些宏会在常量的末尾放置一个 lulllull(如有必要)。例如,对于 ILP32,INT64_C(1) 会在常量 1 后面附加 ll;对于 LP64,则附加 l

用来使常量成为最长类型的宏包括 INTMAX_C(c)UINTMAX_C(c)。这些宏对于指定转换为 LP64 的指导原则中介绍的常量类型会非常有用。

<inttypes.h> 定义的限制

<inttypes.h> 定义的限制是用于为各种整数类型指定最小值和最大值的常量,其中包括每个定宽类型的最小值(INT8_MININT64_MIN 等)和最大值(如 INT8_MAXINT64_MAX 等)及其对应的无符号的最小值和最大值。

该文件还提供了每个最短长度类型的最小值和最大值,其中包括 INT_LEAST8_MININT_LEAST64_MININT_LEAST8_MAXINT_LEAST64_MAX 等及其对应的无符号的最小值和最大值。

最后,该文件定义了支持的最长整数类型的最小值和最大值,其中包括 INTMAX_MININTMAX_MAX 及其对应的无符号的最小值和最大值。

格式字符串宏

<inttypes.h> 文件还提供了用于指定 printfscanf 格式说明符的宏。实际上,这些宏会根据内置于宏名称中的参数的位数,在格式说明符前面放置一个 lll,将参数指定为 longlong long 类型。

printf(3C) 的宏以十进制、八进制、无符号和十六进制格式列显 8 位、16 位、32 位和 64 位整数以及最短和最长整数类型。例如,以十六进制表示法列显 64 位整数:

int64_t i;

printf("i =%" PRIx64 "\n", i);

同样,scanf(3C) 的宏也以十进制、八进制、无符号和十六进制格式读取 8 位、16 位、32 位和 64 位整数以及最长整数类型。例如,读取无符号的 64 位十进制整数:

uint64_t u;

scanf("%" SCNu64 "\n", &u);

请勿毫无限制地使用这些宏,最好将其与定宽类型一起使用。有关更多详细信息,请参阅定宽的整数类型一节。