Oracle® Developer Studio 12.5:C 用户指南

退出打印视图

更新时间: 2016 年 7 月
 
 

8.2 实现单一源代码

以下各节介绍可用于编写支持 32 位和 64 位编译的单一源代码的一些可用资源。

8.2.1 派生类型

使用系统派生类型使代码对于 32 位和 64 位编译环境均安全,这是一种好的编程做法。使用派生数据类型时,只有系统派生类型由于数据模型更改或移植而需要更改。

系统 include 文件 <sys/types.h><inttypes.h> 包含有助于使应用程序对于 32 位和 64 位编译环境均安全的常量、宏和派生类型。

8.2.1.1 <sys/types.h>

在应用程序源文件中包含 <sys/types.h> 以访问 _LP64_ILP32 的定义。此头文件还包含适当时应使用的多个基本派生类型。尤其是以下类型更为重要:

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

  • dev_t 用于设备号。

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

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

  • size_t 反映内存中对象的大小(以字节为单位)。

  • ssize_t 供返回字节计数或错误提示的函数使用。

  • time_t 以秒为单位计时。

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

8.2.1.2 <inttypes.h>

include 文件 <inttypes.h> 提供有助于使代码与显式指定大小的数据项兼容(无论编译环境如何)的常量、宏和派生类型。它包含用于处理 8 位、16 位、32 位和 64 位对象的机制。<inttypes.h> 提供的基本功能包括:

  • 定宽整型

  • 诸如 uintptr_t 的有用类型

  • 常量宏

  • 限制

  • 格式字符串宏

以下各节提供有关 <inttypes.h> 基本功能的更多信息。

定宽整型

<inttypes.h> 提供的定宽整型包括带符号整型(如 int8_tint16_tint32_tint64_t)和无符号整型(如 uint8_tuint16_tuint32_tuint64_t)。

定义为可容纳规定位数的最短整型的派生类型包括 int_least8_tint_least64_tuint_least8_tuint_least64_t 等。

对于循环计数器和文件描述符等操作,使用 intunsigned int 是安全的。对于数组索引,使用 long 也是安全的。但是,不应不加选择地使用这些定宽类型。可将定宽类型用于下列各项的显式二进制表示:

  • 磁盘数据

  • 通过数据线

  • 硬件寄存器

  • 二进制接口规范

  • 二进制数据结构

诸如 unintptr_t 的有用类型

<inttypes.h> 文件包括大小足以容纳一个指针的带符号整型和无符号整型。这些类型以 intptr_tuintptr_t 形式提供。此外,<inttypes.h> 还提供 intmax_tuintmax_t,后两者是可用的最长(以位为单位)带符号整型和无符号整型。

使用 uintptr_t 类型作为指针的整型而非基本类型,如 unsigned long。尽管在 ILP32 和 LP64 数据模型中,unsigned long 与指针的长度相同,但如果使用 uintptr_t,则在数据模型更改时,只有 uintptr_t 的定义受影响。通过此方法可以将代码移植到许多其他系统,也是一种在 C 中表达意图更清晰的方法。

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

常量宏

使用宏 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> 定义的限制是用于指定各种整型的最小值和最大值的常量,这些限制包括每个定宽类型的最小值(如 INT8_MININT64_MIN 等)和最大值(如 INT8_MAXINT64_MAX 等)及其对应的无符号的最小值和最大值。

<inttypes.h> 文件还提供每个最短长度类型的最小值和最大值,这些类型包括 INT_LEAST8_MININT_LEAST64_MININT_LEAST8_MAXINT_LEAST64_MAX 等及其对应的无符号的最小值和最大值。

最后,<inttypes.h> 还定义支持的最长整型的最小值和最大值,这些类型包括 INTMAX_MININTMAX_MAX 及其对应的无符号的最小值和最大值。

格式字符串宏

<inttypes.h> 文件包括指定了 printf(3C)scanf(3C) 格式说明符的宏。实质上,如果宏名称内置了参数的位数,这些宏将在格式说明符前面添加 lll,以便将参数标识为 longlong long

printf(3C) 的某些宏以十进制、八进制、无符号和十六进制格式输出最短和最长整型,如下例所示。

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

同样,scanf(3C) 的宏以十进制、八进制、无符号和十六进制格式读取最短和最长整型。

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

不要不加区别地使用这些宏。最好将它们与定宽整型中介绍的定宽类型一起使用。

8.2.2 使用 lint 进行检查

lint 程序的 -errchk 选项检测潜在的 64 位端口问题。也可以指定 cc -v,该选项指示编译器执行更严格的附加语义检查。-v 选项还会针对指定文件启用某些类似 lint 的检查。

将代码增强到 64 位安全时,应使用 Oracle Solaris 操作系统中出现的头文件,因为这些文件具有 64 位编译环境的派生类型和数据结构的正确定义。

使用 lint 检查为 32 位和 64 位编译环境编写的代码。指定 -errchk=longptr64 选项可生成 LP64 警告。同时使用 -errchk=longptr64 标志来检查是否可将代码移植到具有下述特征的环境中:长整型和指针的长度为 64 位而无格式整型的长度为 32 位。即使使用了显式强制类型转换, -errchk=longptr64 标志也会检查指针表达式和长整型表达式对无格式整型的赋值。

使用 -errchk=longptr64,signext 选项查找符合以下条件的代码:其中标准 ISO C 值保留规则允许在无符号整型表达式中使用带符号整型值的符号扩展。

如果只想检查要在 Oracle Solaris 64 位编译环境中运行的代码,请使用 lint-m64 选项。

lint 警告显示错误代码的行号、描述问题的消息以及是否涉及指针的说明。警告消息还指明涉及的数据类型的长度。如果确定涉及指针并且知道数据类型的长度,便可以查找特定的 64 位问题,并避免 32 位和更短类型之间的已有问题。

但请注意,尽管 lint 会提供有关潜在 64 位问题的警告,但也无法检测所有问题。另外在许多情况下,符合应用程序意图且正确无误的代码会生成警告。

通过在上一行中放置 “NOTE(LINTED(“<optional message”>))” 形式的注释,可以禁止对指定代码行发出警告。如果要 lint 忽略某些代码行(如强制类型转换和赋值),则此注释指令很有用。使用 “NOTE(LINTED(“<optional message”>))” 注释时请务必谨慎,因为它可能会掩盖真实问题。使用 NOTE 时,请包括 note.h。有关更多信息,请参阅 lint 手册页。