(转)#Pragma用法
Author:Jeffrey
????? 在制定ANSI C標準時,引入了pragma提示符,這個指示符來自Ada。#pragma用于向編譯器提示一些信息,諸如把某個特定的函數擴展成內聯,或者取消邊界檢查,它并非C所固有。
目錄:
(0)?? 前言
(1) #pragma message能夠在編譯信息輸出窗口中輸出相應的信息
(2) #pragma code_seg能夠設置程序中函數代碼存放的代碼段,開發驅動程序的時會用到
(3) #pragma? once若用在頭文件的最開始處就能夠保證頭文件被編譯一次
(4) #pragma? hdrstop表示預編譯頭文件到此為止
(5) #pragma? resource "*.dfm"表示把*.dfm文件中的資源加入工程
(6) #pragma warning允許有選擇性的修改編譯器的警告消息的行為
(7) #pragma comment將一個注釋記錄放入一個對象文件或可執行文件中
(8) #pragma data_seg建立一個新的數據段并定義共享數據
???????? 應用1:在DLL中定義一個共享的,有名字的數據段
???????? 應用2: data_seg控制應用程序的啟動次數
(9) 其他用法
(0)前言
?????? #Pragma 指令的作用是設定編譯器的狀態或者是指示編譯器完成一些特定的動作。#pragma 指令對每個編譯器給出了一個方法,在保持與C和C++語言完全兼容的情況下,給出主機或操作系統專有的特征。依據定義,編譯指示是機器或操作系統專有的,且對于每個編譯器都是不同的。其格式一般為: #Pragma?? Para其中Para為參數,下面來看一些常用的參數。?
(1) #Pragma message參數能夠在編譯信息輸出窗口中輸出相應的信息
?????? 這對于源代碼信息的控制是非常重要的。其使用方法為:Pragma?? message(“消息文本”) 。當我們在程序中定義了許多宏來控制源代碼版本的時候,我們自己有可能都會忘記有沒有正確的設置這些宏,此時我們可以用這條指令在編譯的時候就進行檢查。假設我們希望判斷自己有沒有在源代碼的什么地方定義了_X86這個宏可以用下面的方法???????????????
1?#ifdef?? _X86?2?#pragma message(“_X86 macro activated!”)??????????????
3?#endif?
若定義了_X86,程序編譯時就會在顯示“_X86 macro activated!”。我們就不會因為不記得自己定義的一些特定的宏而抓耳撓腮了 。
(2) #pragma code_seg能夠設置程序中函數代碼存放的代碼段,
???? 開發驅動程序的時候就會使用到它。格式如下 :
#pragma code_seg( [ [ { push | pop}, ] [ identifier, ] ][ "segment-name" [, "segment-class" ] ]) ;
??? 該指令用來指定函數在.obj文件中存放的節,觀察OBJ文件可以使用VC自帶的dumpbin命令行程序 ,如果code_seg沒有帶參數的話,則函數在OBJ文件中存放在默認在.text節中。push (可選參數) 將一個記錄放到內部編譯器的堆棧中,可選參數可以為一個標識符或者節名???? pop(可選參數) 將一個記錄從堆棧頂端彈出,該記錄可以為一個標識符或者節名???? identifier (可選參數) 當使用push指令時,為壓入堆棧的記錄指派的一個標識符,當該標識符被刪除的時候和其相關的堆棧中的記錄將被彈出堆棧???? "segment-name" (可選參數) 表示函數存放的節名 例如:???
2?void func1() {???????????????? }????????????
3?//將函數存放在.my_data1節中
4?#pragma code_seg(".my_data1")
5?void func2() {????????????????? }????????????
6?//r1為標識符,將函數放入.my_data2節中?????????????
7?#pragma code_seg(push, r1, ".my_data2")?????????????
8?void func3() {? }
9?int main() {}????
(3)#pragma? once (比較常用)若用在頭文件的最開始處就能夠保證頭文件被編譯一次.
??? 一般在整個工程中我們只要包含頭文件一次就夠了,若多個.c/.cpp 文件中都要包含同一個頭文件,比如 Windows.h,那很多聲明等等豈不是有兩次了?解決這個問題的傳統的方法是在頭文件開始出用 #define 定義一個宏,比如 Windows.h中:
2?#define?? _WINDOWS_???????????????
3?#endif?
?
這樣就可以避免被包含多次。但是這樣的后果是代碼的可讀性較差 (個人觀點),VC給我們提供了另外一個途徑,那就是在文件的前面加上:????????????????? #pragma?? once”
?
(4)#pragma? hdrstop表示預編譯頭文件到此為止
?????? 后面的頭文件不進行預編譯。BCB可以預編譯頭文件以加快鏈接的速度,但如果所有頭文件都進行預編譯又可能占太多磁盤空間,所以使用這個選項排除一些頭文件.有時單元之間有依賴關系,比如單元A依賴單元B,所以單元B要先于單元A編譯。你可以用#pragma?? startup指定編譯優先級,如果使用了#pragma?? package(smart_init) ,BCB就會根據優先級的大小先后編譯。
(5)#pragma? resource "*.dfm"表示把*.dfm文件中的資源加入工程。
*.dfm中包括窗體外觀的定義。?
(6) #pragma warning允許有選擇性的修改編譯器的警告消息的行為
指令格式如下:
#pragma warning( warning-specifier : warning-number-list [;warning-specifier :? warning-? number-list...])??
#pragma warning( push[ ,n ] )????????????????
#pragma warning( pop )
主要用到的警告表示有如下幾個:
??? once:只顯示一次(警告/錯誤等)消息????
?? default:重置編譯器的警告行為到默認狀態????????
?? 1,2,3,4:四個警告級別??????????
?? disable:禁止指定的警告信息?????????????
?? error:將指定的警告信息作為錯誤報告????????????????
?#pragma?? warning( disable: 4507? 34; once : 4385; error : 164?? ) 等價于:#pragma?? warning(disable:4507?? 34)?? //? 不顯示4507和34號警告信息???????????????????
2??#pragma?? warning(error:164)?? //?? 把164號警告信息作為一個錯誤。????????????????????
3??#pragma?? warning( push )//保存所有警告信息的現有的警告狀態。????????????????????
4??#pragma?? warning( push,n)//保存所有警告信息的現有的警告狀態,并且把全局警告等級設定為n。???????????????????? #pragma?? warning( pop )//向棧中彈出最后一個警告信息,在入棧和出棧之間所作的一切改動取消。例如:????????????????? #pragma?? warning(?? push?? )??????????????????
5??#pragma?? warning(?? disable?? :?? 4705?? )???????????????????
6??#pragma?? warning(?? disable?? :?? 4706?? )????????????????????
7??#pragma?? warning(?? disable?? :?? 4707?? )??????????????????? //.???????????????????
8??#pragma?? warning(?? pop?? )???????? 在這段代碼的最后,重新保存所有的警告信息(包括4705,4706和4707)。????
(7)pragma?? comment將一個注釋記錄放入一個對象文件或可執行文件中
該指令的格式為:#pragma comment( "comment-type" [, commentstring] )? comment-type(注釋類型):可以指定為五種預定義的標識符的其中一種,五種預定義的標識符為:
compiler:將編譯器的版本號和名稱放入目標文件中,本條注釋記錄將被編譯器忽略,如果你為該記錄類型提供了commentstring參數,編譯器將會產生一個警告。例如:#pragma comment( compiler )?? ;?????
exestr: 鏈接時,將commentstring參數放入到可執行文件中,當操作系統加載可執行文件的時候,該參數字符串不會被加載到內存中.但是,該字符串可被dumpbin之類的程序查找出并打印出來,你可以用這個標識符將版本號碼之類的信息嵌入到可執行文件中!????????????
lib:用來將一個庫文件鏈接到目標文件中 比如我們連接的時候用到了WSock32.lib,你當然可以不辭辛苦地把它加入到你的工程中。但是我覺得更方便的方法是使用#pragma指示符,指定要連接的庫:
linker:將一個鏈接選項放入目標文件中,你可以使用這個指令來代替由命令行傳入的或者在開發環境中設置的鏈接選項,你可以指定/include選項來強制包含某個對象,例如:????????????????????????????????????
1?#pragma comment(linker, "/include:__mySymbol")
你可以在程序中設置下列鏈接選項 /DEFAULTLIB? /EXPORT?????? /INCLUDE? /MERGE? / SECTION??? 這些選項在這里就不一一說明了,詳細信息請看msdn!?????????????
user:將一般的注釋信息放入目標文件中commentstring參數包含注釋的文本信息,這個注釋記錄將被鏈接器忽略,例如:????
1?#pragma comment( user, "Compiled on " __DATE__ " at " __TIME__ )?
(8)#pragma data_seg建立一個新的數據段并定義共享數據
格式為: #pragma data_seg ("shareddata") HWND sharedwnd=NULL;//共享數據?
??????????? #pragma data_seg()
應用1:在DLL中定義一個共享的,有名字的數據段。
注意:a、這個數據段中的全局變量能夠被多個進程共享。否則多個進程之間無法共享DLL中的全局變量。???????
b、共享數據必須初始化,否則微軟編譯器會把沒有初始化的數據放到.BSS段中,從而導致多個進程之間的共享行為失敗。????? 假如在一個DLL中這么寫:
2?int g_Value; // 全局變量未初始化?????????????????
3?#pragma data_seg()// DLL提供兩個接口函數:????????????????? int GetValue()????????????????????????? {??????????????????????????
4?? return g_Value;??????????????????????????
5?}??????????????????
6?void SetValue(int n)?????????????????????????? {??????????????????????????
7?? g_Value = n;
8?}?????? 然后啟動兩個都調用了這個DLL的進程A和B,假如A調用了SetValue(5); B接著調用int m = GetValue(); 那么m的值不一定是5,而是個未定義的值。因為DLL中的全局數據對于每一個調用他的進程而言,是私有的,不能共享的。假如您對g_Value進行了初始化,那么g_Value就一定會被放進MyData段中。換句話說,假如A調用了SetValue(5); B接著調用int m = GetValue(); 那么m的值就一定是5!這就實現了跨進程之間的數據通信!
應用2: data_seg控制應用程序的啟動次數???????
有的時候我們可能想讓一個應用程序只啟動一次,就像單件模式(singleton)一樣,實現的方法可能有多種,這里說說用#pragma data_seg來實現的方法,很是簡潔便利。應用程序的入口文件前面加上:
2?int app_count =?0;
3?#pragma data_seg()??
4?#pragma comment(linker,"/SECTION:flag_data,RWS")????
5?//然后程序啟動的地方加上???????????????
6?if(app_count>0)??
7?// 如果計數大于0則退出應用程序。????????????????????????????? {?????????????????????????????
8?//MessageBox(NULL, "已經啟動一個應用程序", "Warning", MB_OK);
9?//printf("no%d application", app_count);
10??return FALSE;??????????????????????????????
11?}
12?app_count++;
(9)其他用法
??? 編譯程序可以用#pragma指令激活或終止該編譯程序支持的一些編譯功能。例如,對循環優化功能:
2?#pragma loop_opt(off)?????? // 終止
??? 有時,程序中會有些函數會使編譯器發出你熟知而想忽略的警告,如?? “Parameter xxx is never used in function xxx”,可以這樣:
1?#pragma warn —100
2?//Turn off the warning message for warning #100?????????????????
3?int insert_record(REC *r)??????????????????
4?{ /* function body */ }??????????????????
5?#pragma warn +100? // Turn the warning message for warning #100 back on
函數會產生一條有唯一特征碼100的警告信息,如此可暫時終止該警告。 每個編譯器對#pragma的實現不同,在一個編譯器中有效在別的編譯器中幾乎無效??蓮木幾g器的文檔中查看。
轉載于:https://www.cnblogs.com/phonefans/archive/2008/12/24/1361028.html
總結
以上是生活随笔為你收集整理的(转)#Pragma用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 建站常用代码
- 下一篇: 经济危机下企业倒闭的真相