C-lanugage的可攜性是公認的, 可以跨平台執行.

所以各平台之間的compiler應該儘可能的符合可攜性的要求.

但是為了提高執行效率, 符合各平台的機器特徵做一些特殊動作, 例如撰寫組合語言, 使用co-processor, 使用特殊記憶體配置, 使用特殊的compiler能力...等等會使用到#pragma 的語法以達到目的而又不影響沒有這些能力的平台或compile的編譯.

或 許你會認為用#ifdef也可以達到目的, 但是#ifdef的方式必須在command line指定一堆定義是很麻煩的, 而且一些特殊能力用#ifdef 也定義不出來. 況且使用你寫的source code的人不見得了解該如何定義以符合他的使用平台或compiler的需求.

compiler看到#pragma時如果後面的定義是它不認得的, 它不會理會; 相反的看得懂得compiler就會去執行它.

如 果你是很專業的程式師, 而且考慮跨平台且讓別人可以用你的source code, 那麼很難用一個範例就可以搞懂, 因為它牽涉很複雜的一些規範, 你可以上www.gnu.org去看看他們的規定, GNU是一些熱心軟體發展的人士, 願意提供原始碼貢獻世界的人組成的團體, 依循他們的規範是比較正確的方向(很有學問的).

如果你只是用你現在的compiler時發現這個compiler有一些特殊功能可以提升你的效率, 只要照著做就對了, 沒有什麼大學問, 因為#pragma最有可能的用法就是啟動compiler的特殊能力而不會造成跨平台時一般能力的執行.


編譯指示 #pragma 是用來告知編譯器某些特殊指示,例如不要輸出錯誤訊息,抑制警告訊息,或者加上記憶體漏洞檢查機制等。這些指示通常不是標準的 C 語言所具備的,而是各家編譯器廠商或開發者所制定的,以便讓編譯器可以具有某些特殊的選項。


#pragma pack() "是表示什麼意思呢?

在這裡我先解釋"#pragma"的作用,"#pragma"就像是compiler的功能選擇開關, 也就是#pragma是用來設定complier的選項,跟你在complier後加 -Zp -Xk 等等設定是一樣的。使用它其實就如同你在dos下使用compiler時,在命令列輸入那些參數一樣,所達到的功能是一致的,像在 Watcom C/C++ 中 "#pragma off (check_stack)", 代表的是把WC++的stack檢查關閉,當然你也可以從命令列輸入參數做到一樣的功能,不過有點不一樣的,用"#pragma",你可以選擇所需要這麼處理的程式區段,所以比命令列更方便更好用.不過"#pragma"所提供的功能切換在不同的compiler上並不相同,所以要特別注意.

接下來進入主題,到底"#pragma pack(1)"是做什麼的?其實"#pragma pack( )"就是要compiler照我們的意思去做記憶體aligment(對齊)的工作,在Win32下為了提高記憶體存取效率,所以記憶體配置(對齊)的預設值是以DWORD(4BYTES也就是32bits)為單位,因此在配置struct的記憶體空間的時候,往往會造成struct內部的資料在記憶體位址上並不連續,在我們的程式之中,如果不是用指標去存取這些資料,可能還不會出錯,可是如果我們真的用指標去存取的話,由於資料排列不連續,我們可能會讀不到我們想要的值,這還不打緊,如果這個結構是傳址給Win API來取得資料,那就問題大條了,因為API會以為struct內部的記憶體位址是連續的,所以會造成錯誤,像我之前寫"在Win95/98下存取邏輯磁區"那篇文章的範例程式時,就為此吃足苦頭,不但結果不正確,還一直當機,後來才發現是記憶體aligment的問題,為了讓struct內部的記憶體位址是連續的,這時我們就必需要用"#pragma pack(1)"這個命令,來讓compiler把這個struct,以BYTE為單位做記憶體aligment,如此一來struct使用時就不會出錯了.

"#pragma pack()"有幾個值可供設定,如下所述,"#pragma pack(1)"是對齊BYTE,"#pragma pack(2)"是對齊WORD,而"#pragma pack( )"等於"#pragma pack(4)",就是對齊DWORD,另外,還有"#pragma pack(8)",以及"#pragma pack(16)"可以選用,所以我們只要將struct的定義區段,用"#pragma pack(1)"和"#pragma pack( )"包起來,就可以了使struct正確被存取了

BB 發表在 痞客邦 PIXNET 留言(0) 人氣()