Linux應用程序移植到64位系統 (1)

發表于:2007-05-26來源:作者:點擊數: 標簽:
隨著 64 位體系結構的普及,針對 64 位系統準備好您的 Linux? 軟件已經變得比以前更為重要。在本文中,您將學習如何在進行語句聲明、賦值、位移、類型轉換、字符串格式化以及更多操作時,防止出現可移植性 缺陷 。 Linux 是可以使用 64 位處理器的跨平臺操
隨著 64 位體系結構的普及,針對 64 位系統準備好您的 Linux? 軟件已經變得比以前更為重要。在本文中,您將學習如何在進行語句聲明、賦值、位移、類型轉換、字符串格式化以及更多操作時,防止出現可移植性缺陷。

    Linux 是可以使用 64 位處理器的跨平臺操作系統之一,現在 64 位的系統在服務器和桌面端都已經非常常見了。很多開發人員現在都面臨著需要將自己的應用程序從 32 位環境移植到 64 位環境中。隨著 Intel? Itanium? 和其他 64 位處理器的引入,使軟件針對 64 位環境做好準備變得日益重要了。

    與 UNIX? 和其他類 UNIX 操作系統一樣,Linux 使用了 LP64 標準,其中指針和長整數都是 64 位的,而普通的整數則依然是 32 位的。盡管有些高級語言并不會受到這種類型大小不同的影響,但是另外一些語言(例如 C 語言)卻的確會受到這種影響。

    將應用程序從 32 位系統移植到 64 位系統上的工作可能會非常簡單,也可能會非常困難,這取決于這些應用程序是如何編寫和維護的。很多瑣碎的問題都可能導致產生問題,即使在一個編寫得非常好的高度可移植的應用程序中也是如此,因此本文將對這些問題進行歸納總結,并給出解決這些問題的一些方法建議。

    64 位的優點

    32 位平臺有很多限制,這些限制正在阻礙大型應用程序(例如數據庫)開發人員的工作進展,尤其對那些希望充分利用計算機硬件優點的開發人員來說更是如此??茖W計算通常要依賴于浮點計算,而有些應用程序(例如金融計算)則需要一個比較狹窄的數字范圍,但是卻要求更高的精度,其精度高于浮點數所提供的精度。64 位數學運算提供了這種更高精度的定點數學計算,同時還提供了足夠的數字范圍?,F在在計算機業界中有很多關于 32 位地址空間所表示的地址空間的討論。32 位指針只能尋址 4GB 的虛擬地址空間。我們可以克服這種限制,但是應用程序開發就變得非常復雜了,其性能也會顯著降低。

    在語言實現方面,目前的 C 語言標準要求 “long long” 數據類型至少是 64 位的。然而,其實現可能會將其定義為更大。

    另外一個需要改進的地方是日期。在 Linux 中,日期是使用 32 位整數來表示的,該值所表示的是從 1970 年 1 月 1 日至今所經過的秒數。這在 2038 年就會失效。但是在 64 位的系統中,日期是使用有符號的 64 位整數表示的,這可以極大地擴充其可用范圍。

    總之,64 位具有以下優點:

   1. 64 位的應用程序可以直接訪問 4EB 的虛擬內存,Intel Itanium 處理器提供了連續的線性地址空間。

   2. 64 位的 Linux 允許文件大小最大達到 4 EB(2 的 63 次冪),其重要的優點之一就是可以處理對大型數據庫的訪問。

    Linux 64 位體系結構

    不幸的是,C 編程語言并沒有提供一種機制來添加新的基本數據類型。因此,提供 64 位的尋址和整數運算能力必須要修改現有數據類型的綁定或映射,或者向 C 語言中添加新的數據類型。

    表 1. 32 位和 64 位數據模型

 ILP32LP64LLP64ILP64
char 8 8 8 8
short 16 16 16 16
int 32 32 32 64
long 32 64 32 64
long long 64 64 64 64
指針 32 64 64 64
    這 3 個 64 位模型(LP64、LLP64 和 ILP64)之間的區別在于非浮點數據類型。當一個或多個 C 數據類型的寬度從一種模型變換成另外一種模型時,應用程序可能會受到很多方面的影響。這些影響主要可以分為兩類:

    數據對象的大小。編譯器按照自然邊界對數據類型進行對齊;換而言之,32 位的數據類型在 64 位系統上要按照 32 位邊界進行對齊,而 64 位的數據類型在 64 位系統上則要按照 64 位邊界進行對齊。這意味著諸如結構或聯合之類的數據對象的大小在 32 位和 64 位系統上是不同的。

    基本數據類型的大小。通常關于基本數據類型之間關系的假設在 64 位數據模型上都已經無效了。依賴于這些關系的應用程序在 64 位平臺上編譯也會失敗。例如,sizeof (int) = sizeof (long) = sizeof (pointer) 的假設對于 ILP32 數據模型有效,但是對于其他數據模型就無效了。

    總之,編譯器要按照自然邊界對數據類型進行對齊,這意味著編譯器會進行 “填充”,從而強制進行這種方式的對齊,就像是在 C 結構和聯合中所做的一樣。結構或聯合的成員是根據最寬的成員進行對齊的。清單 1 對這個結構進行了解釋。

    清單 1. C 結構


struct test {
            int i1;
            double d;
            int i2;
            long l;
            }
            

    表 2 給出了這個結構中每個成員的大小,以及這個結構在 32 位系統和 64 位系統上的大小。

    表 2. 結構和結構成員的大小


結構成員在 32 位系統上的大小在 64 位系統上的大小
struct test {    
int i1; 32 位 32 位
  32 位填充
double d; 64 位 64 位
int i2; 32 位 32 位
  32 位填充
long l; 32 位 64 位
}; 結構大小為 20 字節 結構大小為 32 字節

    注意,在一個 32 位的系統上,編譯器可能并沒有對變量 d 進行對齊,盡管它是一個 64 位的對象,這是因為硬件會將其當作兩個 32 位的對象進行處理。然而,64 位的系統會對 d 和 l 都進行對齊,這樣會添加兩個 4 字節的填充。

    從 32 位系統移植到 64 位系統

    本節介紹如何解決一些常見的問題:

    聲明表達式賦值數字常數Endianism類型定義位移字符串格式化函數參數

    聲明

    要想讓您的代碼在 32 位和 64 位系統上都可以工作,請注意以下有關聲明的用法:

    根據需要適當地使用 “L” 或 “U” 來聲明整型常量。

    確保使用無符號整數來防止符號擴展的問題。

    如果有些變量在這兩個平臺上都需要是 32 位的,請將其類型定義為 int.如果有些變量在 32 位系統上是 32 位的,在 64 位系統上是 64 位的,請將其類型定義為 long.為了對齊和性能的需要,請將數字變量聲明為 int 或 long 類型。不要試圖使用 char 或 short 類型來保存字節。

    將字符指針和字符字節聲明為無符號類型的,這樣可以防止 8 位字符的符號擴展問題。

    表達式

    在 C/C++ 中,表達式是基于結合律、操作符的優先級和一組數學計算規則的。要想讓表達式在 32 位和 64 位系統上都可以正確工作,請注意以下規則:

    兩個有符號整數相加的結果是一個有符號整數。

    int 和 long 類型的兩個數相加,結果是一個 long 類型的數。

    如果一個操作數是無符號整數,另外一個操作數是有符號整數,那么表達式的結果就是無符號整數。

    int 和 doubule 類型的兩個數相加,結果是一個 double 類型的數。此處 int 類型的數在執行加法運算之前轉換成 double 類型。

    賦值

    由于指針、int 和 long 在 64 位系統上大小不再相同了,因此根據這些變量是如何賦值和在應用程序中使用的,可能會出現問題。下面是有關賦值的一些技巧:

    不要交換使用 int 和 long 類型,因為這可能會導致高位數字被截斷。例如,不要做下面的事情:

 

int i;
            long l;
            i = l;

    不要使用 int 類型來存儲指針。下面這個例子在 32 位系統上可以很好地工作,但是在 64 位系統上會失敗,這是因為 32 位整數無法存放 64 位的指針。例如,不要做下面的事情:

 

unsigned int i, *ptr;
            i = (unsigned) ptr;

不要使用指針來存放 int 類型的值。例如,不要做下面的事情;

 

int *ptr;
            int i;
            ptr = (int *) i;
            

    如果在表達式中混合使用無符號和有符號的 32 位整數,并將其賦值給一個有符號的 long 類型,那么將其中一個操作數轉換成 64 位的類型。這會導致其他操作數也被轉換成 64 位的類型,這樣在對表達式進行賦值時就不需要再進行轉換了。另外一種解決方案是對整個表達式進行轉換,這樣就可以在賦值時進行符號擴展。例如,考慮下面這種用法可能會出現的問題:

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

從數學計算上來說,上面這個黑體顯示的表達式的結果應該是 -1 。但是由于表達式是無符號的,因此不會進行符號擴展。解決方案是將一個操作數轉換成 64 位類型(下面的第一行就是這樣),或者對整個表達式進行轉換(下面第二行):

 

n = (long) i + k;
            n = (int) (i + k);
            


原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97