32位和64位系统对于程序员的影响
一、數據類型特別是int相關的類型在不同位數機器的平臺下長度不同。C99標準并不規定具體數據類型的長度大小,只規定級別。作下比較:
16位平臺
char ? ? ?1個字節8位
short ? ? ? ?2個字節16位
int ? ? ? ? 2個字節16位
long ? ? ?4個字節32位
指針 ? ? ?2個字節
32位平臺
char ? ? ?1個字節8位
short ? ? ? ?2個字節16位
int ? ? ? ? 4個字節32位
long ? ? ?4個字節
long long 8個字節
指針 ? ? ?4個字節
64位平臺
char ? ? ?1個字節
short ? ? ? ?2個字節
int ? ? ? ? 4個字節
long ? ? ?8個字節(區別)
long long 8個字節
指針 ? ? ? ?8個字節(區別)
二、編程注意事項
為了保證平臺的通用性,程序中盡量不要使用long數據庫型。可以使用固定大小的數據類型宏定義:
typedef signed char ? ? ? int8_t
typedef short int ? ? ? ? ?int16_t;
typedef int ? ? ? ? ? ? ? ?int32_t;
# if __WORDSIZE == 64typedef long int ? ? ? ? ? int64_t;# else__extension__typedef long long int ? ? ?int64_t;
#endif
三、使用int時也可以使用intptr_t來保證平臺的通用性,它在不同的平臺上編譯時長度不同,但都是標準的平臺長度,比如64位機器它的長度就是8字節,32位機器它的長度是4字節,定義如下:
#if __WORDSIZE == 64typedef long int ? ? ? ? ? ? intptr_t;#elsetypedef int ? ? ? ? ? ? ? ? ?intptr_t;#endif編程中要盡量使用sizeof來計算數據類型的大小
以上類型定義都有相應的無符號類型。
另外還有ssize_t和size_t分別是sign size_t和unsigned signed size of computer word size。它們也是表示計算機的字長,在32位機器上是int型,在64位機器上long型,從某種意義上來說它們等同于intptr_t和uintptr_t。它們在stddef.h里面定義。需要注意的是socket的accept函數在有些操作系統上使用size_t是不正確的,因為accept接收的int*類型,而size_t可能是long int 類型。后來BSD使用sock_t來替代它。
?
? 從1995年windows 95推出至今,絕大多數windows應用程序都已經從win16平臺轉移到win32平臺,windows 3.x及其代表的16位windows編程技術被迅速打入了冷宮。現在,microsoft公司的軟件工程師們針對intel公司的ia-64處理器構架又開始了64位windows編程(win64)技術的設計,由于windows 98是windows 9x系列中的最后一個產品,所以win64將被包含在正在開發的windows nt 5.0中,當intel的新一代64位處理器merced推出后,軟件開發人員就可以開始使用64位編程技術,nt的企業計算能力勢必會得到極大的提高。
?
因為4gb的地址空間滿足了目前絕大多數應用的需求,win64與win32之間的差異遠小于win32與win16之間的差異,所以win64不會像win32取代win16那樣迅速取代win32。在今后相當長的一段時間內,win64將與win32和平共處,相互補充。軟件開發人員需要根據應用的特點選擇開發平臺,或者同時建立應用程序的win64和win32版本,由于win64與win32編程區別不大,在使用高級語言編程時只要遵循一定的原則,花費極少量的時間與精力就可以為不同平臺創建相應的版本,并且在多數時候只要對源程序重新編譯連接一次就可以了。
? ·llp64抽象數據模型·
c語言標準中沒有規定整型、長整型和指針等變量各有多少位,而是留給了計算平臺來確定,因此每種系統及其應用都必須采用某種默認的抽象數據模型來作為計算的基礎,win32采用一種稱為llp32的模型,即假定整型、長整型和指針變量的字長都是32位,相應定義的int、uint、long、ulong和handle等數據類型也都是32位,這對于32位windows編程環境來說是合理的規定。如果win64中把整型、長整型和指針變量的字長都改為64位,那么不僅要占有以前兩倍的存儲空間,而且現有的應用程序及其使用的大多數數據類型都需要作更改,實現兩種平臺之間的可移植性就變得相當困難了。事實上,在引入64位平臺后,應用程序需要實現64位尋址,并只在少數地方需要用到64位數據,而多數時候使用32位數據就足夠了,因此,win64采用了一種稱為llp64的抽象數據模型,除了把指針變量擴展到了64位外,整型和長整型變量等基本數據類型仍然保持32位。由于基本數據類型都保持32位不變,所以存儲在磁盤上的數據不用改變其結構和大小,遠程或本地進程之間的共享數據(如內存映射文件)也不用改變其結構和大小,這就大大減輕了程序員的工作量。
為了實現同一份源代碼既能在win32下運行,也能在win64下運行,定義llp64模型只是走出了第一步,接下來還要定義一些與指針相關的數據類型,如對指針進行計算時需要的數據類型等,編譯器會根據目標平臺來確定這些數據類型是32位還是64位。這些新的數據類型是用c語言的int和long類型定義的,因此保持了對win32及部分windows api函數的向后兼容性,microsoft計劃在windows nt 5.0的beta 2版包含這些新數據類型,并逐漸移植所有的windows api函數到64位平臺,程序員在nt 5.0 beta 2版及相應的platform sdk推出后就可以開始使用這些數據類型了,當64位平臺正式推出后,所編寫的程序多數只需重新編譯連接一次即可生成64位版本。
·新的數據類型·
新數據類型共有三類:固定精度數據類型(fixed-precision data types)、指針精度數據類型(pointer-precision data type)和指定精度指針(specific-precision pointers)。
1.固定精度數據類型在win32和win64中有相同的字長,為了便于記憶,它們的名字中包含了其字長。
·int32和int64:字長分別為32位和64位的有符號整型數;
·long32和long64:字長分別為32位和64位的有符號長整型數;
·uint32和uint64:字長分別為32位和64位的無符號整型數;
·ulong32和ulong64:字長分別為32位和64位的無符號長整型數。
2.指針精度數據類型與目標平臺的指針的字長相同(由編譯器來確定),這樣可以把指針安全地轉換成指針精度數據類型來進行代數運算和位運算,而不用編程時處處考慮目標平臺的類型。
·int-ptr和uint-ptr:指針精度的有符號和無符號整型數,win32下字長為32位,win64下字長為64位;
·ssize-t和size-t:指針精度的計數器,用于確定指針精度數據類型的字長,前者為有符號計數器。
3.特定精度指針在win32和win64中都保持相同的字長,因此只在某些特殊情況下才有用。
·-ptr64(64位指針):在win32中,32位指針通過符號擴展生成一個64位指針,擴展的結果可能沒有任何意義,不能再當做指針來使用;
·-ptr32(32位指針):在win64中,64位指針通過截去高32位生成一個32位指針,結果可能沒有任何意義,也不能再當做指針來使用。
使用這些新的數據類型可以更清晰地顯示出程序中哪些地方進行的計算實質上與指針相關,這樣在進行類型轉換時就不容易出錯,而win32中原來定義的數據類型就沒有這個優點,因此新數據類型有利于我們編寫出更健壯的代碼,并且為將來移植到64位平臺做好了準備。
·輔助開發工具·
在win64下編程與在win32下編程區別很小,因為大家熟悉的windows api函數除了涉及到指針的參數的類型可能改變外,其他沒有什么更多的變化,程序員原有的知識仍然有用。為了幫助程序員修改現有的源代碼,轉而使用新的數據類型,microsoft將在nt 5.0 beta 2版中包含一些開發輔助工具,其中包括一個定義新數據類型的頭文件basetsd.h和一個語法檢查器。語法檢查器可以檢查出源程序中不正確的類型轉換、指針截斷及其他一些與64位相關的問題。例如它會指出下面的代碼存在著4311號指針截斷警告:
buff = (puchar)srbcontrol;
(ulong)buffer += srbcontrol->headerlength;
為了消除警告,應該把ulong改為uint-ptr,這樣才能保證這段代碼既能在win32上運行,也能在win64上運行。程序員的目標是消除所有語法檢查器發出的警告,尤其是4311號指針截斷警告。
·編程規則·
為了順利實現兩種平臺的源代碼級可移植性,程序員應按照以下規則來編寫程序或者修改已有程序。
1.不能將指針轉換成int、uint、long、ulong、dword等字長固定為32位的類型,如果需要對指針做運算,應把指針轉換為int-ptr或uint-ptr,這兩種類型在不同平臺上才有正確的字長。另外,由于handle實質上是一個指針(void *),因此把handle轉換成long或ulong等類型也是不正確的。
2.如果確定需要對指針進行截斷,那么應使用ptrtolong()和ptrtoulong()兩個函數(在basetsd.h中定義)來進行,它們可以屏蔽掉指針截斷警告,不過截斷的結果不能夠再當指針使用了。
3.當某個api函數的out參數能返回一個指針時,應小心謹慎處理參數,在win32中,可以把一個ulong變量的地址進行強制轉換后傳遞給api函數,返回的指針就保存在ulong變量中,但在win64中,返回的指針有64位,如果使用ulong變量的話就會破壞其他變量的內容,正確并且簡單的方法是直接定義一個指針變量,把指針變量的地址作為參數傳遞給api函數。
4.謹慎處理多態參數。在win32中,一個函數可以用一個dword參數來接受多態參數,即該參數在不同情況下可能具有不同的意義,如解釋成整型數或指針。在win64中,如果一個多態參數可能被解釋成指針,那么決不能把多態參數設為dword類型,而應設為uint-ptr或pvoid類型。win32自身的一部分api函數(如raiseexception())因為不符合該條規則而需要進行修改。
5.使用新的get/setwindowlongptr和get/setclasslongptr api函數。如果在窗口或類的數據區中存放了指針,就需要調用上面的函數來存取相應的變量,為了幫助程序員在編程中正確處理這一點,頭文件winuser.h把索引值gwl-wndproc、gwl-hinstance、gwl-hwdparent和gwl_userdata的定義取消了,轉而定義了新的索引值gwlp-wndproc、gwlp-hinstance、gwlp-hwdparent和gwlp-userdata。這樣下面的代碼將會引起編譯錯誤:
setwindowlong(hwnd,gwl-wndproc,(long)mywndproc);
因為gw-wndproc沒有定義,正確的代碼應為:
setwindowlongptr(hwnd,gwlp-wndproc,(int-ptr)mywndproc);
6.許多窗口和類的數據結構中包含了指針,因此不能在代碼中強行指定偏移量來訪問數據成員,而應使用field-offset宏來計算偏移量。
7.由于lparam、wparam和lresult通常用來存放指針或整數,在win64中它們全部被擴展成為64位,因此不能把它們與dword、ulong、uint、int、int和long等類型混用,否則可能會無意識地把它們截短了。
關于在win64環境下編程還需要注意的其他問題,以及win64平臺下api函數的變化及新增函數,有興趣的讀者可到microsoft的web站點查閱相關資料,或者參考最新版的platform sdk及msdn oline library。
··························································································································································································
C/C++僅僅定義了這些基本數據類型之間的關系,并沒有定義嚴格定義它們的字長。在不同的平臺上,根據編譯器不同的實現,它們的字長如下表所示:
| 數據類型 | LP64 | ILP64 | LLP64 | ILP32 | LP32 | 
| char | 8 | 8 | 8 | 8 | 8 | 
| short | 16 | 16 | 16 | 16 | 16 | 
| _int32 | N/A | 32 | N/A | N/A | N/A | 
| int | 32 | 64 | 32 | 32 | 16 | 
| long | 64 | 64 | 32 | 32 | 32 | 
| long long | N/A | N/A | 64 | N/A | N/A | 
| pointer | 64 | 64 | 64 | 32 | 32 | 
在這張表中,LP64,ILP64,LLP64是64位平臺上的字長模型,ILP32和LP32是32位平臺上的字長模型。
LP64意思是long和pointer是64位,ILP64指int,long,pointer是64位,LLP指long long和pointer是32-bit的。ILP32指int,long和pointer是32位的,LP32指long和pointer是32位的。
32位Windows采用的是LP32數據模型,64位Windows采用的是LLP64數據模型。 所以,Windows上的32位程序設計和64位程序設計最大的不同(也就是IP32和LLP64的不同),就在于指針的長度不同??由32位變成了64位。 Win32 API在很多情況下,都需要將整數轉換成指針或者相反。在 32 位的硬件上不會有問題,其中指針的大小和整數的大小是相同的,但在 64 位的硬件上卻完全不一樣。 為此M$搞了個所謂的“多態類型”:對于特定的精度,您可以使用固定精度的數據類型。不管處理器的詞大小如何,它們的大小都是一致的。大多數這些類型都在它們的名稱中包含精度,可以從下面的表中看出:
| 表 1. 固定精度的數據類型 | |
| 類型 | 定義 | 
| DWORD32???????????? | 32 位無符號整數 | 
| DWORD64 | 64 位無符號整數 | 
| INT32 | 32 位有符號整數 | 
| INT64 | 64 位有符號整數 | 
| LONG32 | 32 位有符號整數 | 
| LONG64 | 64 位有符號整數 | 
| UINT32 | 無符號 INT32 | 
| UINT64 | 無符號 INT64 | 
| ULONG32 | 無符號 LONG32 | 
| ULONG64 | 無符號 LONG64 | 
此外,當您需要數據類型的精度隨著處理器詞大小變化時,請使用指針精度數據類型。這些類型又稱為“多態”數據類型。這些類型通常以 _PTR 后綴結尾,如下面的表格所示:
| 表 2. 指針精度的數據類型 | |
| 類型 | 定義 | 
| DWORD_PTR?????????????? | 指針精度的無符號長類型 | 
| HALF_PTR | 指針大小的一半。用于包含一個指針和兩個小型字段的結構中 | 
| INT_PTR | 指針精度的有符號整型 | 
| LONG_PTR | 指針精度的有符號長類型 | 
| SIZE_T | 指針可以引用的最大字節數。用于必須跨指針的整個范圍的計數 | 
| SSIZE_T | 有符號 SIZE_T | 
| UHALF_PTR | 無符號 HALF_PTR | 
| UINT_PTR | 無符號 INT_PTR | 
| ULONG_PTR | 無符號 LONG_PTR | 
| LPARAM | 與 LONG_PTR 為同義詞,(在WTypes.h 中定義) | 
| WPARAM | 與 UINT_PTR 為同義詞,(在 WTypes.h 中定義) | 
通過整數參數傳遞參數或上下文信息的所有 Win32 API 都更改為使用這些新的類型。
此外,還出現了定長指針:POINTER_32和POINTER_64: #define POINTER_32 __ptr32 #define POINTER_64 __ptr64 PS:M$DN中說是在Basetsd.h中定義的,但實際上是在WinNT.h中定義的。總結
以上是生活随笔為你收集整理的32位和64位系统对于程序员的影响的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 12.7亿入股五星电器背后,京东家电想成
- 下一篇: 首席商学院新媒体运营创始人黎想:爆火抖音
