32-64升级注意事项

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

32bit-64bit porting work注意事项

64位服务器逐步普及,各条产品线对64位升级的需求也不断加大。在本文中,主要讨论向64位平台移植现有32位代码时,应注意的一些细小问题。

什么样的程序需要升级到64位?

理论上说,64位的操作系统,对32位的程序具有良好的兼容性,即使全部换成64位平台,依然可以良好的运行32位的程序。因此,许多目前在32位平台上运行良好的程序也许不必移植,有选择,有甄别的进行模块的升级,对我们工作的展开,是有帮助的。

什么样的程序需要升级到64位呢?

除非程序有以下要求:

●需要多于4GB的内存。

●使用的文件大小常大于2GB。

●密集浮点运算,需要利用64位架构的优势。

●能从64位平台的优化数学库中受益。

ILP32和LP64数据模型

32位环境涉及"ILP32"数据模型,是因为C数据类型为32位的int、long、指针。而64位环境使用不同的数据模型,此时的long和指针已为64位,故称作"LP64"数据模型。下面

由上表我们可以看出,32位到64位的porting工作,主要就是处理长度变化所引发的各种问题。在32位平台上很多正确的操作,在64位平台上都不再成立。例如:long->int等,会出现截断问题等。下面将详细阐述具体遇到的问题,并给出修改策略。

截断问题

截断问题是在32-64porting工作中最容易遇到的问题。

部分的截断问题能够被编译器捕捉到,采用-Wall –W进行编译,永远没有坏处。这种问题处理方法也非常简单,举个例子来说:

long mylong;

(void) scanf("%d", &mylong);// warning: int format, different type arg (arg 2)

long mylong;

(void) scanf("%ld", &mylong);// ok

但有很多情况下,一些截断性问题并不能被良好的诊断出来。

例如:

long a;

int b;

b = a;

在这种情况下,编译器会直接进行转换(截断处理),编译阶段不报任何警告。当a的数据范围在2G范围内时,不会出问题,但是超出范围,数据将出现问题。

另外,采用了强制转换的方式,使一些隐患被保留了下来,例如:

long mylong;

(void) scanf("%d",(int*)&mylong);//编译成功,但mylong的高位未被赋值,有可能导致问题。

采用pclint可以有效的检查这种问题,但是,在繁多的warning 中,找到需要的warning,并不是一件容易的事情。

因此,在做平台移植的时候,对于截断问题,最根本的还是逐行阅读代码,详细检测。

在编码设计的时候,尽量保持使用变量类型的一致性,避免发生截断问题。

建议:在接口以及数据结构的定义中不要使用指针,long,以及用long定义的类型(size_t, ssize_t, off_t, time_t),由于字长的变化,这些类型不能32/64位兼容。

一个讨厌的类型size_t:在32bit平台上,它的原形是unsigned int,而在64bit平台上,它的原形式unsigned long。这导致在printf等使用时:无论使用%u或者%lu都会有一个平台报warning。目前我们的解决办法是:采用%lu打印,并且size_t强制转换为unsinged long。在小尾字节序(Little-endian)的系统中,这种转换是安全的。

常量有效性问题

那些以十六进制或二进制表示的常量,通常都是32位的。例如,无符号32位常量0xFFFFFFFF通常用来测试是否为-1;

#define INV ALID_POINTER_V ALUE 0xFFFFFFFF

然而,在64位系统中,这个值不是-1,而是4294967295;在64位系统中,-1正确的值应为0xFFFFFFFFFFFFFFFF。要避免这个问题,在声明常量时,使用const,并且带上signed 或unsigned。

例如:

const signed int INV ALID_POINTER_V ALUE = 0xFFFFFFFF;

上面一行代码将会在32位和64位系统上都运行正常。或者,根据需要适当地使用“L”

或“U”来声明整型常量。

又比如对最高位的设置,通常我们的做法是定义如下的常量0x80000000,但是可移植性更好的方法是使用一个位移表达式:1L << ((sizeof(long) * 8) - 1);

参数问题

在参数的数据类型是由函数原型定义的情况中,参数应该根据标准规则转换成这种类型

。在参数类型没有指定的情况中,参数会被转换成更大的类型

。在64 位系统上,整型被转换成64 位的整型值,单精度的浮点类型被转换成双精度的浮点类型

。如果返回值没有指定,那么函数的缺省返回值是int 类型的

。避免将有符号整型和无符号整型的和作为long 类型传递(见符号扩展问题)

请看下面的例子:

long function (long l);

int main () {

int i = -2;

unsigned k = 1U;

long n = function (i + k);

}

上面这段代码在 64 位系统上会失败,因为表达式 (i + k) 是一个无符号的 32 位表达式,在将其转换成 long 类型时,符号并没有得到扩展。解决方案是将一个操作数强制转换成 64 位的类型。

扩充问题(指针范围越界)

扩充问题与代码截断问题刚好相反。请看下面的例子:

int baidu_gunzip(char* inbuf,int len,char* outbuf,int* size)

{

……

ret=bd_uncompress((Byte*)outbuf,(uLongf*)size,

(Byte*)(inbuf+beginpos),inlen);

}

这是ullib库中baidugz模块的一段代码。在这段代码中,将int型的指针改为long型的指针传递给了bd_uncompress函数。在32位系统中,由于int与long都是32bit,程序没有任何问题,但在64位系统中,将导致指针控制的范围在调用函数中扩展为原来的2倍,这将有可能导致程序出core,或指示的值不正确。这种问题比较隐蔽,很难发现,但危害极大,需要严格注意。

解决方法:加强对指针型参数的检查,看是否有范围扩充的问题。

相关文档
最新文档