从32位到64位,根本性的区别在于两种数据类型发生了变化:long和pointer。在32位环境下,两者长度都是32位,也就是4个字节;而在64位环境下都是8个字节。所以当你把pointer或者long型数据赋给int型时,会发生数据截断(data truncation)。
32位应用的数据模型我们称作ILP32(之所以这样命名,是因为int,long,pointer都是32位),而64位应用则采用LP64模型(意味着long,pointer变成64位了,其他的不变)。在当前的32位环境下,我们可以认为int,long,pointer是等价的,因为它们占用相同的字节,于是就有很多混用的情况;但是到了64位的时代,long和Poniter的大小都改变了,原来的假设不再成立。
char *p = &something;
p = (char *) ((int)p & PAGEOFFSET);
% cc ..
warning: conversion of pointer loses bits
char *p = &something;
p = (char *) ((uintptr_t)p & PAGEOFFSET);
int A = 0;
long B = 0;
long C = 0;
...
A = B + C;
% cc
warning: assignment of 64-bit integer to 32-bit integer
struct T
{
int i;
long j;
int k;
char *p;
};
在ILP32中,sizeof(T)应该是16字节;在LP64中,应该是32!因为此时long/char *的对齐字节都变为8,为了保证满足对齐要求,i/k都被扩展为8字节了,又例如:
struct T
{
char *p;
long j;
int i;
int k;
};
union U
{
double _d;
long _l[2];
};
在ILP32中,两者大小相同都是8字节;移植到LP64,前者不变,后者为16字节,应改为:
union U
{
double _d;
int _l[2];
};
无类型的整数常量就是 (unsigned) int 类型的,这可能会导致在位移时出现被截断的问题。
例如,在下面的代码中,a的最大值可以是 31。这是因为1 << a是 int 类型的:
long t = 1 << a;
要在 64 位系统上进行位移,应该使用1L,如下所示:
long t = 1L << a;
char *ptr = &something;
printf (%x\n", ptr);
上面的代码在 64 位系统上会失败,它只会显示低 4 字节的内容。解决方案是使用%p,%p兼容ILP32和L64,另外就是作为目标的buffer必须够长:
char *ptr = &something;
printf (%p\n", ptr);
* clock_t, which represents the system time in clock ticks
* dev_t, which is used for device numbers
* off_t, which is used for file sizes and offsets
* ptrdiff_t, which is the signed integral type for the result of subtracting two pointers
* size_t, which reflects the size, in bytes, of objects in memory
* ssize_t, which is used by functions that return a count of bytes or an error indication
* time_t, which counts time in seconds
例如,sizeof和strlen返回值都是size_t类型,当它们的返回值赋值给int类型的变量时,在ILP32位上没有问题,但在LP64上并且返回值大于2G时会发生截断:
int bufferSize = (int) sizeof (something);
int length = (int) strlen(str);
size_t bufferSize = (size_t) sizeof (something);
size_t length = (size_t) strlen(str);
提醒:应用程序在32位机移植到64位机时,由于long指针等大小的改变,会发生数据截断等错误,应该将编译器的警告级别调高,反复调试,有可能一个小小的警告会让程序死掉。另外在编译时采用-errchk=longptr64选项可以检查出把long/pointer表达式转换为int的情况,包括显式转换。