科技时代新浪首页 > 科技时代 > 学园 > 正文

将32位代码向64位平台移植的注意事项(2)


http://www.sina.com.cn 2006年02月10日 07:39 天极yesky

    缺少原型的截断

  如果一个函数被调用时没有指定函数原型,返回值将是32位的int。不使用原型的代码可能会发生意料之外的数据截断,由此导致一个分割错误。编译器捕捉到了例1中第12行的这个错误。

  char *name = (char *) getlogin();

  编译器假定函数返回一个int值,并截短结果指针。这行代码在ILP32数据模型下工作正常,因为此时的int和指针是同样长度,换到LP64模型中,就不一定正确了,甚至于类型转换都不能避免这个错误,因为getlogin()在返回之后已经被截断了。

  要修正这个问题,需包括头文件<unistd.h>,其中有getlogin()的函数原型。

  格式指定符

  如果对64位long、指针使用了32位格式指定符,将导致程序错误。编译器捕捉到了例1中第15行的这个错误。

(void) scanf("%d", &mylong);

  注意,scanf将向变量mylong中插入一个32位的值,而剩下的4字节就不管了。要修正这个问题,请在scanf中使用%ld指定符。

  第18行也演示了在printf中的一个类似的问题:

  printf("mylong: %d pointer: %x \n", mylong, myptr);

  要修正此处的错误,mylong应使用%ld,对myptr使用 %p而不是%x。

  赋值截断

  有关编译器发现赋值截断的一个例子在第16行中:

  myint = mylong;

  这在ILP32模型下不会有任何问题,因为此时的int、long都是32位,而在LP64中,当把mylong赋值给myint时,如果数值大于32位整数的最大值时,数值将被截短。

  被截断的参数

  编译器发现的下一个错误在第17行中,虽然myfunc函数只接受一个int参数,但调用时却用了一个long,参数在传递时会悄无声息地被截断。

  转换截断

  转换截断发生在把long转换成int时,比如说例1中的第19行:

myint = (int) mylong;

  导致转换截断的原因是int与long非同样长度。这些类型的转换通常在代码中以如下形式出现:

int length = (int) strlen(str);

  strlen返回size_t(它在LP64中是unsigned long),当赋值给一个int时,截断是必然发生的。而通常,截断只会在str的长度大于2GB时才会发生,这种情况在程序中一般不会出现。虽然如此,也应该尽量使用适当的多态类型(如size_t、uintptr_t等等),而不要去管它最下面的基类型是什么。

  一些其他的细小问题

  编译器可捕捉到移植方面的各种问题,但不能总指望编译器为你找出一切错误。

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

#define INVALID_POINTER_VALUE 0xFFFFFFFF

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

const signed int INVALID_POINTER_VALUE = 0xFFFFFFFF;

  这行代码将会在32位和64位系统上都运行正常。

  其他有关于对常量硬编码的问题,都是基于对ILP32数据模型的不当认识,如下:

int **p; p = (int**)malloc(4 * NO_ELEMENTS);

  这行代码假定指针的长度为4字节,而这在LP64中是不正确的,此时是8字节。正确的方法应使用sizeof():

int **p; p = (int**)malloc( sizeof(*p) * NO_ELEMENTS);

  注意对sizeof()的不正确用法,例如:

sizeof(int) = = sizeof(int *);

  这在LP64中是错误的。

  符号扩展

  要避免有符号数与无符号数的算术运算。在把int与long数值作对比时,此时产生的数据提升在LP64和ILP32中是有差异的。因为是符号位扩展,所以这个问题很难被发现,只有保证两端的操作数均为signed或均为unsigned,才能从根本上防止此问题的发生。

  例2:

long k;
int i = -2;
unsigned int j = 1;
k = i + j;

printf("Answer: %ld\n", k);

  你无法期望例2中的答案是-1,然而,当你在LP64环境中编译此程序时,答案会是4294967295。原因在于表达式(i+j)是一个unsigned int表达式,但把它赋值给k时,符号位没有被扩展。要解决这个问题,两端的操作数只要均为signed或均为unsigned就可。像如下所示:

k = i + (int) j

[上一页] [1] [2] [3] [4] [下一页]

发表评论

爱问(iAsk.com)



评论】【论坛】【收藏此页】【 】【多种方式看新闻】【下载点点通】【打印】【关闭




科技时代意见反馈留言板 电话:010-82628888-5595   欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

Copyright © 1996 - 2006 SINA Corporation, All Rights Reserved

新浪公司 版权所有