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

缺少原型的截断
  如果一个函数被调用时没有指定函数原型,返回值将是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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值