win32和win64編程注意事項

來源:互聯網
上載者:User
資料模型(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位外,整型和長整型變數等基礎資料型別 (Elementary Data Type)仍然保持32位。由於基礎資料型別 (Elementary Data Type)都保持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。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.