#pragma comment和#pragma 预处理指令详解
??? 例如,#pragma?? comment(lib,"Ws2_32.lib")表示鏈接Ws2_32.lib這個庫。 和在工程設置里寫上鏈入Ws2_32.lib的效果一樣,不過這種方法寫的 程序別人在使用你的代碼的時候就不用再設置工程settings了。
#pragma comment( comment-type [,"commentstring"] )comment-type是一個預定義的標識符,指定注釋的類型,應該是compiler,exestr,lib,linker之一。 commentstring是一個提供為comment-type提供附加信息的字符串, Remarks: 1、compiler:放置編譯器的版本或者名字到一個對象文件,該選項是被linker忽略的。 2、exestr:在以后的版本將被取消。 3、lib:放置一個庫搜索記錄到對象文件中,這個類型應該是和commentstring(指定你要Liner搜索的lib的名稱和路徑) 這個庫的名字放在Object文件的默認庫搜索記錄的后面,linker搜索這個這個庫就像你在命令行輸入這個命令一樣。你可以 在一個源文件中設置多個庫記錄,它們在object文件中的順序和在源文件中的順序一樣。如果默認庫和附加庫的次序是需要 區別的,使用Z編譯開關是防止默認庫放到object模塊。 4、linker:指定一個連接選項,這樣就不用在命令行輸入或者在開發環境中設置了。 只有下面的linker選項能被傳給Linker.
-
/DEFAULTLIB
-
/EXPORT
-
/INCLUDE
-
/MANIFESTDEPENDENCY
-
/MERGE
-
/SECTION
忽略所有默認庫 (/NODEFAULTLIB) 選項重寫 /DEFAULTLIB:library。如果在兩者中指定了相同的 library 名稱,忽略庫 (/NODEFAULTLIB:library) 選項將重寫 /DEFAULTLIB:library。
(2)/EXPORT:entryname[,@ordinal[,NONAME]][,DATA]
使用該選項,可以從程序導出函數,以便其他程序可以調用該函數。也可以導出數據。通常在 DLL 中定義導出。entryname 是調用程序要使用的函數或數據項的名稱。ordinal 在導出表中指定范圍在 1 至 65,535 的索引;如果沒有指定 ordinal,則 LINK 將分配一個。NONAME 關鍵字只將函數導出為序號,沒有 entryname。
DATA 關鍵字指定導出項為數據項。客戶程序中的數據項必須用 extern __declspec(dllimport) 來聲明。
有三種導出定義的方法,按照建議的使用順序依次為:
源代碼中的 __declspec(dllexport)
.def 文件中的 EXPORTS 語句
LINK 命令中的 /EXPORT 規范
所有這三種方法可以用在同一個程序中。LINK 在生成包含導出的程序時還創建導入庫,除非生成中使用了 .exp 文件。
LINK 使用標識符的修飾形式。編譯器在創建 .obj 文件時修飾標識符。如果 entryname 以其未修飾的形式指定給鏈接器(與其在源代碼中一樣),則 LINK 將試圖匹配該名稱。如果無法找到唯一的匹配名稱,則 LINK 發出錯誤信息。當需要將標識符指定給鏈接器時,請使用 Dumpbin 工具獲取該標識符的修飾名形式。
/INCLUDE 選項通知鏈接器將指定的符號添加到符號表。
若要指定多個符號,請在符號名稱之間鍵入逗號 (,)、分號 (;) 或空格。在命令行上,對每個符號指定一次 /INCLUDE:symbol。
鏈接器通過將包含符號定義的對象添加到程序來解析 symbol。該功能對于添包含不會鏈接到程序的庫對象非常有用。用該選項指定符號將通過 /OPT:REF 重寫該符號的移除。
MSDN描述(http://msdn.microsoft.com/zh-cn/library/aa273890.aspx): Places a comment record into an object file or executable file. The comment-type is one of five predefined identifiers, described below, that specify the type of comment record. The optional commentstring is a string literal that provides additional information for some comment types. Because commentstring is a string literal, it obeys all the rules for string literals with respect to escape characters, embedded quotation marks ("), and concatenation.?
compiler?
Places the name and version number of the compiler in the object file. This comment record is ignored by the linker. If you supply a commentstring parameter for this record type, the compiler generates a warning.?
exestr?
Places commentstring in the object file. At link time, this string is placed in the executable file. The string is not loaded into memory when the executable file is loaded; however, it can be found with a program that finds printable strings in files. One use for this comment-record type is to embed a version number or similar information in an executable file.?
lib?
Places a library-search record in the object file. This comment type must be accompanied by a commentstring parameter containing the name (and possibly the path) of the library that you want the linker to search. Since the library name precedes the default library-search records in the object file, the linker searches for this library just as if you had named it on the command line. You can place multiple library-search records in the same source file; each record appears in the object file in the same order in which it is encountered in the source file.?
linker?
Places a linker option in the object file. You can use this comment-type to specify a linker option instead placing the option on the Link tab of the Project Settings dialog box. For example, you can specity the /include option to force the inclusion of a symbol:?
#pragma comment(linker, "/include:__mySymbol")?
user?
Places a general comment in the object file. The commentstring parameter contains the text of the comment. This comment record is ignored by the linker.?
The following pragma causes the linker to search for the EMAPI.LIB library while linking. The linker searches first in the current working directory and then in the path specified in the LIB environment variable.?
#pragma comment( lib, "emapi" )?
The following pragma causes the compiler to place the name and version number of the compiler in the object file:?
#pragma comment( compiler )?
Note For comments that take a commentstring parameter, you can use a macro in any place where you would use a string literal, provided that the macro expands to a string literal. You can also concatenate any combination of string literals and macros that expand to string literals. For example, the following statement is acceptable:?
#pragma comment( user, "Compiled on " __DATE__ " at " __TIME__ )
=================================================================================
#pragma 預處理指令詳解
(http://social.msdn.microsoft.com/Forums/zh-CN/visualcpluszhchs/thread/106caa63-24bb-41c5-816d-a56996df10b8/):
在所有的預處理指令中,#Pragma?? 指令可能是最復雜的了,它的作用是設定編譯器的狀態或?
者是指示編譯器完成一些特定的動作。#pragma指令對每個編譯器給出了一個方法,在保持與?
C和C++語言完全兼容的情況下,給出主機或操作系統專有的特征。依據定義,編譯指示是機器?
或操作系統專有的,且對于每個編譯器都是不同的。?
其格式一般為:?? #Pragma?? Para?
其中Para 為參數,下面來看一些常用的參數。?
(1)message 參數。?? Message?? 參數是我最喜歡的一個參數,它能夠在編譯信息輸出窗?
口中輸出相應的信息,這對于源代碼信息的控制是非常重要的。其使用方法為:?
#Pragma?? message(“消息文本”)?
當編譯器遇到這條指令時就在編譯輸出窗口中將消息文本打印出來。?
當我們在程序中定義了許多宏來控制源代碼版本的時候,我們自己有可能都會忘記有沒有正?
確的設置這些宏,此時我們可以用這條指令在編譯的時候就進行檢查。假設我們希望判斷自?
己有沒有在源代碼的什么地方定義了_X86這個宏可以用下面的方法?
#ifdef?? _X86?
#Pragma?? message(“_X86?? macro?? activated!”)?
#endif?
當我們定義了_X86這個宏以后,應用程序在編譯時就會在編譯輸出窗口里顯示“_?
X86?? macro?? activated!”。我們就不會因為不記得自己定義的一些特定的宏而抓耳撓腮了?。?
(2)另一個使用得比較多的pragma參數是code_seg。格式如:?
#pragma?? code_seg(?? [\section-name\[,\section-class\]?? ]?? )?
它能夠設置程序中函數代碼存放的代碼段,當我們開發驅動程序的時候就會使用到它。?
(3)#pragma?? once ?(比較常用)?
只要在頭文件的最開始加入這條指令就能夠保證頭文件被編譯一次,這條指令實際上在VC6?
中就已經有了,但是考慮到兼容性并沒有太多的使用它。?
(4)#pragma?? hdrstop 表示預編譯頭文件到此為止,后面的頭文件不進行預編譯。BCB可以預?
編譯頭文件以加快鏈接的速度,但如果所有頭文件都進行預編譯又可能占太多磁盤空間,所?
以使用這個選項排除一些頭文件。?
有時單元之間有依賴關系,比如單元A依賴單元B,所以單元B要先于單元A編譯。你可以用#p?
ragma?? startup指定編譯優先級,如果使用了#pragma?? package(smart_init)?? ,BCB就會根據?
優先級的大小先后編譯。?
?(5)#pragma?? resource?? \*.dfm\ 表示把*.dfm文件中的資源加入工程。*.dfm中包括窗體外觀的定義。?
(6)#pragma?? warning(?? disable?? :?? 4507?? 34;?? once?? :?? 4385;?? error?? :?? 164?? )?
等價于:?
#pragma?? warning(disable:4507?? 34)?? //?? 不顯示4507和34號警告信息?
#pragma?? warning(once:4385)?? //?? 4385號警告信息僅報告一次?
#pragma?? warning(error:164)?? //?? 把164號警告信息作為一個錯誤。?
同時這個pragma?? warning?? 也支持如下格式:?
#pragma?? warning(?? push?? [?? ,n?? ]?? )?
#pragma?? warning(?? pop?? )?
這里n代表一個警告等級(1---4)。?
#pragma?? warning(?? push?? )保存所有警告信息的現有的警告狀態。?
#pragma?? warning(?? push,?? n)保存所有警告信息的現有的警告狀態,并且把全局警告等級設定為n。?
#pragma?? warning(?? pop?? )向棧中彈出最后一個警告信息,在入棧和出棧之間所作的一切改動取消。例如:?
#pragma?? warning(?? push?? )?
#pragma?? warning(?? disable?? :?? 4705?? )?
#pragma?? warning(?? disable?? :?? 4706?? )?
#pragma?? warning(?? disable?? :?? 4707?? )?
//.......?
#pragma?? warning(?? pop?? )?
在這段代碼的最后,重新保存所有的警告信息(包括4705,4706和4707)。?
(7)pragma?? comment(...)?
該指令將一個注釋記錄放入一個對象文件或可執行文件中。?常用的lib關鍵字,可以幫我們連入一個庫文件。?
(8)·通過#pragma?? pack(n)改變C編譯器的字節對齊方式???
在C語言中,結構是一種復合數據類型,其構成元素既可以是基本數據類型(如int、long、float等)的變量,也可以是一些復合數據類型(如數組、 結構、聯合等)的數據單元。在結構中,編譯器為結構的每個成員按其自然對界(alignment)條件分配空間。各個成員按照它們被聲明的順序在內存中順 序存儲,第一個成員的地址和整個結構的地址相同。?
?????????? 例如,下面的結構各成員空間分配情況:?
struct?? test???
{?
?????????? char?? x1;?
?????????? short?? x2;?
?????????? float?? x3;?
?????????? char?? x4;?
};?
?????????? 結構的第一個成員x1,其偏移地址為0,占據了第1個字節。第二個成員x2為short類型,其起始地址必須2字節對界,因此,編譯器在x2和x1之間填 充了一個空字節。結構的第三個成員x3和第四個成員x4恰好落在其自然對界地址上,在它們前面不需要額外的填充字節。在test結構中,成員x3要求4字 節對界,是該結構所有成員中要求的最大對界單元,因而test結構的自然對界條件為4字節,編譯器在成員x4后面填充了3個空字節。整個結構所占據空間為 12字節。更改C編譯器的缺省字節對齊方式?
?????????? 在缺省情況下,C編譯器為每一個變量或是數據單元按其自然對界條件分配空間。一般地,可以通過下面的方法來改變缺省的對界條件:?
·?? 使用偽指令#pragma?? pack?? (n),C編譯器將按照n個字節對齊。?
?????????? ·?? 使用偽指令#pragma?? pack?? (),取消自定義字節對齊方式。?
?????????? 另外,還有如下的一種方式:?
?????????? ·?? __attribute((aligned?? (n))),讓所作用的結構成員對齊在n字節自然邊界上。如果結構中有成員的長度大于n,則按照最大成員的長度來對齊。?
?????????? ·?? __attribute__?? ((packed)),取消結構在編譯過程中的優化對齊,按照實際占用字節數進行對齊。?
以上的n?? =?? 1,?? 2,?? 4,?? 8,?? 16...?? 第一種方式較為常見。?
應用實例?
在網絡協議編程中,經常會處理不同協議的數據報文。一種方法是通過指針偏移的方法來得到各種信息,但這樣做不僅編程復雜,而且一旦協議有變化,程序修 改起來也比較麻煩。在了解了編譯器對結構空間的分配原則之后,我們完全可以利用這一特性定義自己的協議結構,通過訪問結構的成員來獲取各種信息。這樣做, 不僅簡化了編程,而且即使協議發生變化,我們也只需修改協議結構的定義即可,其它程序無需修改,省時省力。下面以TCP協議首部為例,說明如何定義協議結 構。其協議結構定義如下:?
#pragma?? pack(1)?? //?? 按照1字節方式進行對齊?
struct?? TCPHEADER???
{?
?????????? short?? SrcPort;?? //?? 16位源端口號?
?????????? short?? DstPort;?? //?? 16位目的端口號?
?????????? int?? SerialNo;?? //?? 32位序列號?
?????????? int?? AckNo;?? //?? 32位確認號?
?????????? unsigned?? char?? HaderLen?? :?? 4;?? //?? 4位首部長度?
?????????? unsigned?? char?? Reserved1?? :?? 4;?? //?? 保留6位中的4位?
?????????? unsigned?? char?? Reserved2?? :?? 2;?? //?? 保留6位中的2位?
?????????? unsigned?? char?? URG?? :?? 1;?
?????????? unsigned?? char?? ACK?? :?? 1;?
?????????? unsigned?? char?? PSH?? :?? 1;?
?????????? unsigned?? char?? RST?? :?? 1;?
?????????? unsigned?? char?? SYN?? :?? 1;?
?????????? unsigned?? char?? FIN?? :?? 1;?
?????????? short?? WindowSize;?? //?? 16位窗口大小?
?????????? short?? TcpChkSum;?? //?? 16位TCP檢驗和?
?????????? short?? UrgentPointer;?? //?? 16位緊急指針?
};???
#pragma?? pack()?? //?? 取消1字節對齊方式????
總結
以上是生活随笔為你收集整理的#pragma comment和#pragma 预处理指令详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于WDM驱动开发的不错资料(来自cod
- 下一篇: GetCurrentProcessID、