天天看點

win32和win64程式設計注意事項 資料模型(LP32 ILP32 LP64 LLP64 ILP64 )

資料模型(LP32 ILP32 LP64 LLP64 ILP64 )

32位環境涉及"ILP32"資料模型,是因為C資料類型為32位的int、long、指針。而64位環境使用不同的資料模型,此時的long和指針已為64位,故稱作"LP64"資料模型。

現今所有64位的類Unix平台均使用LP64資料模型,而64位Windows使用LLP64資料模型,除了指針是64位,其他基本類型都沒有變。

 TYPE               LP32  ILP32  LP64  ILP64  LLP64

CHAR                8         8          8         8         8

SHORT             16       16        16       16       16

INT                  16       32        32        64      32

LONG               32       32        64       64       32

LONG LONG     64       64        64       64       64

POINTER          32       32        64       64       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 == 64

typedef long int              int64_t;

# else

__extension__

typedef long long int      int64_t;

#endif

三、使用int時也可以使用intptr_t來保證平台的通用性,它在不同的平台上編譯時長度不同,但都是标準的平台長度,比如64位機器它的長度就是8位元組,32位機器它的長度是4位元組,定義如下:

#if __WORDSIZE == 64

typedef long int                intptr_t;

#else

typedef 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。

繼續閱讀