最佳答案 - 由提问者1年前选出
随着低成本64位平台的来临,加上内存和硬盘价格的不断下跌,无疑为32位程序向64位硬件的移植又加了一把劲,那些科学运算、数据库、消耗大量内存或密集浮点运算的程序也搭上了这一顺风车。在本文中,主要讨论向64位平台移植现有32位代码时,应注意的一些细小问题。
新近的64位平台在二进制上与32位应用程序兼容,这意味着可以非常简单地移植现有的程序。许多目前在32位平台上运行良好的程序也许不必移植,除非程序有以下要求:
·需要多于4GB的内存。
·使用的文件大小常大于2GB。
·密集浮点运算,需要利用64位架构的优势。
·能从64位平台的优化数学库中受益。
否则,只需简单地重新编译一下,就已经足够了。大多数编写良好的程序不费吹灰之力就可移植到64位平台之上,在此假定你的程序编写良好,并熟悉本文将要讨论的问题。
ILP32和LP64数据模型
32位环境涉及"ILP32"数据模型,是因为C数据类型为32位的int、long、指针。而64位环境使用不同的数据模型,此时的long和指针已为64位,故称作"LP64"数据模型。
现今所有64位的类Unix平台均使用LP64数据模型,而64位Windows使用LLP64数据模型,除了指针是64位,其他基本类型都没有变。我们在此主要探讨ILP32到LP64的移植问题,表1显示了ILP32与LP64数据模型的差异。
向64位移植代码时的所有问题差不多都可以总结出一个简单的规律:千万不要认为int、long、指针的长度一样。任何违反这条规律的代码,当运行在LP64数据模型下时,都会出现不同的问题,而且很难找出原因所在。例1中有许多违反这条规律的地方,其在移植到64位平台上时都需要重写。
例1:
1 int *myfunc(int i)
2 {
3 return(&i);
4 }
5
6 int main(void)
7 {
8 int myint;
9 long mylong;
10 int *myptr;
11
12 char *name = (char * ) getlogin();
13
14 printf("Enter a number %s: ", name);
15 (void) scanf("%d", &mylong);
16 myint = mylong;
17 myptr = myfunc(mylong);
18 printf("mylong: %d pointer: %x \n", mylong, myptr);
19 myint = (int)mylong;
20 exit(0);
21
22 }
第一步是要求编译器捕捉到移植时的问题,因所用编译器的不同,选项可能也有所不同,但对IBM XL编译器系列,可用的选项有-qwarn64 -qinfo=pro,为了得到64位可执行文件,可使用选项-q64(如果使用GCC,选项应为-m64,表2中列出了其他可用的GCC选项)。图1是编译例1中代码时的情况。
编译例1中代码时的情况
缺少原型的截断
如果一个函数被调用时没有指定函数原型,返回值将是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,参数在传递时会悄无声息地被截断。