數據類型問題
Linux系統32位與64位GCC編譯器基本數據類型長度對照表
GCC 32位
sizeof(char)=1 sizeof(double)=8 sizeof(float)=4 sizeof(int)=4 sizeof(short)=2 sizeof(long)=4 sizeof(long long)=8 sizeof(long double)=12 sizeof(complex long double)=24 GCC 64位 sizeof(char)=1 sizeof(double)=8 sizeof(float)=4 sizeof(int)=4 sizeof(short)=2 sizeof(long)=8 sizeof(long long)=8 sizeof(long double)=16 sizeof(complex long double)=32
以下爲從網上獲取的信息 ,直接copy過來,以防丟失。
64位操作系統編碼規範 一、Linux及Windows主要類型字節長度
二、不允許使用long型; 三、不允許把int強制轉換爲指針,反之亦然;下面是錯誤的:int i = (int )ptr; 或: void *ptr = (void *)s32Tmp; 四、不允許在不同類型的指針(有繼承關係除外)進行強制轉換,如:int *ipTmp; time_t *tpTmp = *ipTmp;是錯誤的; 五、強烈建議使用帶長度的類型,如:SInt32/UInt64等; 六、必須使用%p打印指針,如printf(“this[%p]\n”,this); 七、強烈建議不要採用scanf,scanf非常危險,Format和參數類型不一致時,非常容易導致越界寫。如果必須使用,則必須認真區別32和64位的操作系統整數長度的差別,需要時,分別針對32和64位編寫代碼; 八、如果編寫動態鏈接庫,必須加上–fPIC編譯選項; 九、採用GCC編譯器時,必須使用-Wlong-long、-Wformat -Wpointer-arith 來發現 64 位編譯問題,並關注相關警告信息; 十、編譯器指示宏定義
十一、 宏使用說明: l 我們的代碼要求同時支持32位和64位版本; l 儘量不要使用與架構相關的宏,如i386/ x86-64/_X86_/Win32等,在同一操作系統中,API一般與架構無關,這樣可以讓代碼具有良好的移植性; l 我們的軟件主要在類Unix(符合POSIX規範,包括Linux)和Windows下運行,優先使用_posix_作爲區別非windows操作系統; l 如果對準備使用的類UNIX下系統調用(API)是否支持其它操作系統沒有把握,可使用_posix_加以標記,待日後移植到其它操作系統時,再測試或修改; Linux 64 位體系結構 不幸的是,C 編程語言並沒有提供一種機制來添加新的基本數據類型。因此,提供 64 位的尋址和整數運算能力必須要修改現有數據類型的綁定或映射,或者向 C 語言中添加新的數據類型。 表 1. 32 位和 64 位數據模型
數據對象的大小。編譯器按照自然邊界對數據類型進行對齊;換而言之,32 位的數據類型在 64 位系統上要按照 32 位邊界進行對齊,而 64 位的數據類型在 64 位系統上則要按照 64 位邊界進行對齊。這意味着諸如結構或聯合之類的數據對象的大小在 32 位和 64 位系統上是不同的。 基本數據類型的大小。通常關於基本數據類型之間關係的假設在 64 位數據模型上都已經無效了。依賴於這些關係的應用程序在 64 位平臺上編譯也會失敗。例如,sizeof (int) = sizeof (long) = sizeof (pointer) 的假設對於 ILP32 數據模型有效,但是對於其他數據模型就無效了。 總之,編譯器要按照自然邊界對數據類型進行對齊,這意味着編譯器會進行 “填充”,從而強制進行這種方式的對齊,就像是在 C 結構和聯合中所做的一樣。結構或聯合的成員是根據最寬的成員進行對齊的。清單 1 對這個結構進行了解釋。 清單 1. C 結構
表 2 給出了這個結構中每個成員的大小,以及這個結構在 32 位系統和 64 位系統上的大小。
表 2. 結構和結構成員的大小
注意,在一個 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/ 中,表達式是基於結合律、操作符的優先級和一組數學計算規則的。要想讓表達式在 32 位和 64 位系統上都可以正確工作,請注意以下規則: 兩個有符號整數相加的結果是一個有符號整數。 int 和 long 類型的兩個數相加,結果是一個 long 類型的數。 如果一個操作數是無符號整數,另外一個操作數是有符號整數,那麼表達式的結果就是無符號整數。 int 和 doubule 類型的兩個數相加,結果是一個 double 類型的數。此處 int 類型的數在執行加法運算之前轉換成 double 類型。 賦值 由於指針、int 和 long 在 64 位系統上大小不再相同了,因此根據這些變量是如何賦值和在應用程序中使用的,可能會出現問題。下面是有關賦值的一些技巧: 不要使用 int 和 long 類型,因爲這可能會導致高位數字被截斷。例如,不要做下面的事情:
不要使用 int 類型來指針。下面這個例子在 32 位系統上可以很好地工作,但是在 64 位系統上會失敗,這是因爲 32 位整數無法存放 64 位的指針。例如,不要做下面的事情:
不要使用指針來存放 int 類型的值。例如,不要做下面的事情;
如果在表達式中混合使用無符號和有符號的 32 位整數,並將其賦值給一個有符號的 long 類型,那麼將其中一個操作數轉換成 64 位的類型。這會導致其他操作數也被轉換成 64 位的類型,這樣在對表達式進行賦值時就不需要再進行轉換了。另外一種解決方案是對整個表達式進行轉換,這樣就可以在賦值時進行符號擴展。例如,考慮下面這種用法可能會出現的問題:
從數學計算上來說,上面這個黑體顯示的表達式的結果應該是 -1 。但是由於表達式是無符號的,因此不會進行符號擴展。解決方案是將一個操作數轉換成 64 位類型(下面的第一行就是這樣),或者對整個表達式進行轉換(下面第二行):
|