1. 程式人生 > >32位程式碼移植到64位需注意問題

32位程式碼移植到64位需注意問題

下面是做32位程式移植到64位程式時資料整理:



---------------------------------------------------------------------------------------------------------------------------------

從32位到64位,根本性的區別在於兩種資料型別發生了變化:long和pointer,當你把pointer或者long型資料賦給int型時,會發生資料截斷(data truncation)。


用lint檢測long/pointer的64位問題
採用-errchk=longptr64選項可以檢查出把long/pointer表示式轉換為int的情況,包括顯式轉換。
 
留心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;
p = (char *) ((int)p & PAGEOFFSET);
% cc ..
warning: conversion of pointer loses bits
 
改用uintptr_t後,無論是32位或者64位都沒問題:
char *p;
p = (char *) ((uintptr_t)p & PAGEOFFSET);


留心int和long
在ILP32中,可能從未對int和long加以區分,因此,混用的情況非常多,看下面程式碼:
int waiting;
long w_io;
long w_swap;
...
waiting = w_io + w_swap;
% cc
warning: assignment of 64-bit integer to 32-bit integer




留心union
union中的成員,必須保持平衡,也就是說,必須保證大小相等才有意義,所以移植時也要注意。
例如:
typedef union {
  double _d;
  long _l[2];
} llx_
在ILP32中,兩者大小相同,都是8位元組;移植到LP64,前者不變,後者為16位元組,此時union已無意義,應改為:
typedef union {
  double _d;
  int _l[2];
} llx_


留心對齊
出於訪問的效率,結構中通常會有所謂的hole,用來保證其中的所有資料成員,起始地址都是對齊模數的倍數。
例如:
struct bar {
  int i;  
  long j; 
  int k; 
  char *p;
};
在ILP32中,sizeof(bar)應該是16位元組;在LP64中,應該是32!因為此時long/char *的對齊模數都變為8,為了保證滿足對齊要求,i/k都被擴充套件為8位元組了。
又例如:
struct bar {
  char *p;
  long j;
  int i;
  int k;
}
此時,無需擴充套件,sizeof(bar)=8+8+4+4=24.


留心常量型別
在常量表達式中,精度的缺失會導致資料截斷,例如:
int i = 32;
long j = 1 << i;
warning: left shift count >= width of type
什麼意思?編譯器抱怨左移的位數超過了資料型別的長度,結果就是j為0。
怎麼修改呢?
int i = 32;
long j = 1L << i:
即可。


留心printf系列函式
在格式化串中,要注意:
%p相容ILP32和L64。
如果有long型引數,必須加上l字首;
另外就是作為目標的buffer必須夠長。


留心sizeof
sizeof返回型別為unsigned long,如果返回給int型變數,可能發生截斷。


留心derived data types
例如,這些定義在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


留心邊緣效應
區域性程式碼發生型別改變,可能導致其他程式碼發生64位轉換,例如函式的返回值由Int變為sszie_t,則所有呼叫該函式並獲取其返回值的地方,都有可能發生意想不到的64位轉換
留心long array 對效率的影響
大型Long/unsigned long陣列,在LP64下,相比ILP32,效率非常低,所以,如果int就足夠,儘量不要使用Long,這一點,對於pointer arrary同樣適用。
1.  對於long型別,會發生位元組數變化,所以要檢查所有使用long型別的地方;


2.  指標在32位系統中是4位元組,而在64位系統中是8位元組,因此所有跟指標位元組數有關的地方必須改掉。典型的情況是:
      1)將struct型別直接存入檔案再讀出來,並且struct中包含指標成員。
      2)使用memset函式直接指定了大小,比如Student ** p = new Student*[num]; memset(p, 4, num);

-----------------------------------------------------------------------------------------------------------------------

主要注意點:指標 32位4個位元組,64位8個位元組;

                   long型32位4個位元組,64位8個位元組;

下面是相關資料連結:

  -----------------------------------------------------------------------------------------------------------------------            

32位C/C++程式移植到64位系統時需要注意的問題

https://blog.csdn.net/vistas_fh/article/details/50858001

C程式將32位程式碼向64位平臺移植的注意事項

https://blog.csdn.net/bytxl/article/details/47813547

64位系統程式碼移植面臨的20個問題

https://blog.csdn.net/john2xy/article/details/20312603