32位程序移植到64位需要考虑的问题
2014-02-23 23:29
766 查看
概述
从32位到64位,根本性的区别在于两种数据类型发生了变化:long和pointer。在32位环境下,两者长度都是32位,也就是4个字节;而在64位环境下都是8个字节。所以当你把pointer或者long型数据赋给int型时,会发生数据截断(data truncation)。1、32位与64位数据模型之间的区别
32位应用的数据模型我们称作ILP32(之所以这样命名,是因为int,long,pointer都是32位),而64位应用则采用LP64模型(意味着long,pointer变成64位了,其他的不变)。在当前的32位环境下,我们可以认为int,long,pointer是等价的,因为它们占用相同的字节,于是就有很多混用的情况;但是到了64位的时代,long和Poniter的大小都改变了,原来的假设不再成立。2、注意int和pointer转换
因为integer与pointer大小相同,所以32位代码中常常把pointer转换为int或者unsigned int,以便算术运算。为了移植,你可以把pointer转换为unsigned long,因为long和pointer都是等长的,无论是在ILP32或LP64。但是,为了使代码更清晰,推荐用uintptr_t,uintptr_t和intptr_t都需要包含头文件inttypes.h。例如:下面代码在64位环境下编译出错:
char *p = &something; p = (char *) ((int)p & PAGEOFFSET); % cc .. warning: conversion of pointer loses bits
改用uintptr_t后,无论是32位或者64位都没问题:
char *p = &something; p = (char *) ((uintptr_t)p & PAGEOFFSET);
3、注意int和long转换
在ILP32中,可能从未对int和long加以区分,因此,混用的情况非常多,看下面代码:int A = 0; long B = 0; long C = 0; ... A = B + C; % cc warning: assignment of 64-bit integer to 32-bit integer
4、结构体字节对齐及大小问题
在结构体中,各个成员的起始地址都是对齐字节的倍数,例如: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; };
此时,无需扩展,sizeof(T)=8+8+4+4=24.
5、注意union
例如:union U { double _d; long _l[2]; };在ILP32中,两者大小相同都是8字节;移植到LP64,前者不变,后者为16字节,应改为:
union U { double _d; int _l[2]; };
6、注意移位操作
无类型的整数常量就是 (unsigned) int 类型的,这可能会导致在位移时出现被截断的问题。例如,在下面的代码中,a的最大值可以是 31。这是因为1 << a是 int 类型的:
long t = 1 << a;要在 64 位系统上进行位移,应该使用1L,如下所示:
long t = 1L << a;
7、字符串格式化
函数printf 及其相关函数都可能成为问题的根源。例如,在 32 位系统上使用%d来打印 int 或 long 类型的值都可以,但是在 64 位平台上,这会导致将 long 类型的值截断成低 32 位的值。对于 long 类型的变量来说,正确的用法是%ld。在下面的例子中,假设指针是 32 位的:
char *ptr = &something; printf (%x\n", ptr);上面的代码在 64 位系统上会失败,它只会显示低 4 字节的内容。解决方案是使用%p,%p兼容ILP32和L64,另外就是作为目标的buffer必须够长:
char *ptr = &something; printf (%p\n", ptr);
8、类型定义
建议您不要使用 C/C++ 中那些在 64 位系统上会改变大小的数据类型来编写应用程序,而是使用一些类型定义或宏来显式地说明变量中所包含的数据的大小和类型,这些定义可以使代码的可移植性更好。例如,在sys/types.h中的数据类型,其大小会随ILP32或者LP64而变化:* 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);
9、注意边缘效应
局部代码发生类型改变,可能导致其他代码发生64位转换,例如函数的返回值由Int变为sszie_t,则所有调用该函数并获取其返回值的地方,都有可能发生意想不到的64位转换。10、注意long array 对效率的影响
大型Long/unsigned long数组,在LP64下,相比ILP32,效率非常低,所以,如果int就足够,尽量不要使用Long,这一点,对于pointer arrary同样适用。11、第三方类库
程序中可能实用了第三方类库,此时要检查第三方类库是否可以在64位机上使用。
相关文章推荐
- 32位程序移植到64位需要考虑的问题
- 32位程序移植到64位需要考虑的问题
- 32位程序移植到64位需要考虑的问题
- 32位程序移植到64位需要考虑的问题
- 32位C/C++程序移植到64位系统时需要注意的问题
- 32位C/C++程序移植到64位系统时需要注意的问题
- C/C++ 32位机器和64位机器 差异问题总结 跨平台 移植问题 语言编程需要注意的64位和32机器的区别
- 关于32位程序在64位系统下运行中需要注意的重定向问题(有图,很清楚)
- 关于32位程序在64位系统下运行中需要注意的重定向问题(有图有真相)(***)
- 移植32位程序到64位时碰到精度问题
- 应对32位程序在64位系统上访问注册表和文件自动转向问题
- 64位进程调用32位dll的解决方法 / 程序64位化带来的问题和思考
- 如何移植32位程序到64位系统
- 应对32位程序在64位系统上访问注册表和文件自动转向问题
- 32位程序访问64位Windows操作系统存放64位系统文件的 \Windows\System32 目录时将遇到重定向目录问题
- 解决.NET 32位程序运行在64位操作系统下的兼容性问题
- 你为什么需要在64位系统下用32位程序
- 应对32位程序在64位系统上访问注册表和文件自动转向问题
- nasm程序从32位到64位平台的移植(三)
- 32位程序在64位Windows7/2008下写注册表不起作用问题