如前所述,32 位环境和 64 位环境之间最大的区别在于两种基础数据类型的变化。
用于 32 位应用程序的 C 数据类型模型是 ILP32 模型,之所以这样命名,是因为类型 int
、long
和指针均为 32 位。LP64 数据模型是用于 64 位应用程序的 C 数据类型模型,业界公司联盟已就此达成一致。之所以这样命名,是因为 long 和指针类型的数据长度会增加到 64 位。其余的 C 类型 int
、short
和 char
均与 ILP32 模型中的相应类型相同。
以下的程序样例 foo.c 直接对比说明了 LP64 数据模型与 ILP32 数据模型的不同结果。同一个程序既可以编译为 32 位程序,也可以编译为 64 位程序。
#include <stdio.h> int main(int argc, char *argv[]) { (void) printf("char is \t\t%lu bytes\n", sizeof (char)); (void) printf("short is \t%lu bytes\n", sizeof (short)); (void) printf("int is \t\t%lu bytes\n", sizeof (int)); (void) printf("long is \t\t%lu bytes\n", sizeof (long)); (void) printf("long long is \t\t%lu bytes\n", sizeof (long long)); (void) printf("pointer is \t%lu bytes\n", sizeof (void *)); return (0); }
32 位编译的结果是:
% cc -O -o foo32 foo.c % foo32 char is 1 bytes short is 2 bytes int is 4 bytes long is 4 bytes long long is 8 bytes pointer is 4 bytes |
64 位编译的结果是:
% cc -xarch=generic64 -O -o foo64 foo.c % foo64 char is 1 bytes short is 2 bytes int is 4 bytes long is 8 bytes long long is 8 bytes pointer is 8 bytes |
缺省编译环境旨在最大化可移植性,即创建 32 位应用程序。
C 整型之间的标准关系仍然适用。
sizeof (char) <= sizeof (short) <= sizeof (int) <= sizeof (long)
表 4–1 列出了基本 C 数据类型及其在 LP32 和 LP64 数据类型模型中的对应长度(以位为单位)。
表 4–1 数据类型的长度(以位为单位)
C 数据类型 |
ILP32 |
LP64 |
---|---|---|
|
8 |
不变 |
|
16 |
不变 |
|
32 |
不变 |
|
32 |
64 |
|
64 |
不变 |
|
32 |
64 |
|
32 |
不变 |
|
32 |
不变 |
|
64 |
不变 |
|
128 |
不变 |
某些旧的 32 位应用程序可互换使用 int
、long
和指针类型。类型为 long
的数据和指针长度在 LP64 数据模型中会增加。需要注意的是,单是这种变化就可导致许多 32 位到 64 位的转换问题。
此外,声明和强制类型转换在说明意图时也会变得非常重要。类型更改时,表达式的求值方式会受到影响。标准 C 转换规则的作用受数据类型长度变化的影响。要充分说明意图,可能需要声明常量的类型。为了确保按照预期的方式对表达式求值,可能还需要在表达式中进行强制类型转换。对表达式进行正确的求值在符号扩展时尤其重要,在这种情况下进行显式强制类型转换可能是实现预期效果所必需的。
对于内置的 C 运算符、格式字符串、汇编语言以及兼容性和互操作性,还会出现其他问题。
本章的其余部分将通过介绍以下内容来给出解决这些问题的建议:
更详细地解释以上概述的问题
介绍某些可用来使代码对于 32 位和 64 位均安全的派生类型和头文件
介绍有助于使代码对于 64 位安全的工具
提供使代码可在 32 位和 64 位环境之间移植的一般规则