#pragma詳細解釋
在#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\] ] ) 它能夠設定程式中函數代碼存放的代碼段,使用沒有section-name字元串的#pragmacode_seg可在編譯開始時将其複位,當我們開發驅動程式的時候就會使用到它。
(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位元組對齊方式
指定連接配接要使用的庫 比如我們連接配接的時候用到了 WSock32.lib,你當然可以不辭辛苦地把它加入到你的工程中。但是我覺得更友善的方法是使用 #pragma 訓示符,指定要連接配接的庫: #pragma comment(lib, "WSock32.lib")
附加:
每種C和C++的實作支援對其主控端或作業系統唯一的功能。例如,一些程式需要精确控制超出資料所在的儲存空間,或着控制特定函數接受參數的方式。#pragma訓示使每個編譯程式在保留C和C++語言的整體相容性時提供不同機器和作業系統特定的功能。編譯訓示被定義為機器或作業系統特定的,并且通常每種編譯程式是不同的。
文法:
#pragma token_string
“token_string”是一系列字元用來給出所需的特定編譯程式指令和參數。數字元号“#”必須是包含編譯指令的行中第一個非空白字元;而空白字元可以隔開數字元号“#”和關鍵字“pragma”。在#pragma後面,寫任何翻譯程式能夠作為預處理符号分析的文本。#pragma的參數類似于宏擴充。
如果編譯程式發現它不認得一個編譯訓示,它将給出一個警告,可是編譯會繼續下去。
為了提供新的預處理功能,或者為編譯程式提供由實作定義的資訊,編譯訓示可以用在一個條件語句内。C和C++編譯程式可以識别下列編譯程式指令。
alloc_text
comment
init_seg*
optimize
auto_inline
component
inline_depth
pack
bss_seg
data_seg
inline_recursion
pointers_to_members*
check_stack
function
intrinsic
setlocale
code_seg
hdrstop
message
vtordisp*
const_seg
include_alias
once
warning
*僅用于C++編譯程式。
#pragma alloc_text( "textsection", function1, ... )
命名特别定義的函數駐留的代碼段。該編譯訓示必須出現在函數說明符和函數定義之間。
alloc_text編譯訓示不處理C++成員函數或重載函數。它僅能應用在以C連接配接方式說明的函數——就是說,函數是用extern "C"連接配接訓示符說明的。如果你試圖将這個編譯訓示應用于一個具有C++連接配接方式的函數時,将出現一個編譯程式錯誤。
由于不支援使用__based的函數位址,需要使用alloc_text編譯訓示來指定段位置。由textsection指定的名字應該由雙引号括起來。
alloc_text編譯訓示必須出現在任何需要指定的函數說明之後,以及這些函數的定義之前。
在alloc_text編譯訓示中引用的函數必須和該編譯訓示處于同一個子產品中。如果不這樣做,使以後一個未定義的函數被編譯到一個不同的代碼段時,錯誤會也可能不會被捕獲。即使程式一般會正常運作,但是函數不會分派到應該在的段。
alloc_text的其它限制如下:
它不能用在一個函數内部。
它必須用于函數說明以後,函數定義以前。
#pragma auto_inline( [{on | off}] )
當指定off時将任何一個可以被考慮為作為自動嵌入擴充候選的函數排除出該範圍。為了使用auto_inline編譯訓示,将其緊接着寫在一個函數定義之前或之後(不是在其内部)。該編譯訓示将在其出現以後的第一個函數定義開始起作用。auto_inline編譯訓示對顯式的inline函數不起作用。
#pragma data_seg( ["section-name"[, "section-class"] ] )
為未初始化資料指定預設段。data_seg編譯訓示除了工作于已初始化資料而不是未初始化的以外具有一樣的效果。在一些情況下,你能使用bss_seg将所有未初始化資料安排在一個段中來加速你的裝載時間。
#pragma bss_seg( "MY_DATA" )
将導緻把#pragma語句之後的未初始化的資料安排在一個叫做MY_DATA的段中。
用bss_seg編譯訓示配置設定的資料不包含任何關于其位置的資訊。
第二個參數section-class是用于相容2.0版本以前的Visual C++的,現在将忽略它。
#pragma check_stack([ {on | off}] )
#pragma check_stack{+ | –}
如果指定off(或者“-”)訓示編譯程式關閉堆棧探測,或者指定on(或“+”)打開堆棧探測。如果沒有給出參數,堆棧探測将根據預設設定決定。該編譯訓示将在出現該訓示之後的第一個函數開始生效。堆棧探測既不是宏和能夠生成嵌入代碼函數的一部分。
如果你沒有給出check_stack編譯訓示的參數,堆棧檢查将恢複到在指令行指定的行為。詳細情況見編譯程式參考。#pragma check_stack和/Gs選項的互相作用情況在表2.1中說明。
表 2.1 使用check_stack編譯訓示
編譯訓示
用/Gs選項編譯?
行為
#pragma check_stack()或#pragma check_stack
是
後續的函數關閉堆棧檢查
否
後續的函數打開堆棧檢查
#pragma check_stack(on)或#pragma check_stack(+)
是或者否
#pragma check_stack(off)或#pragma check_stack(-)
#pragma code_seg( ["section-name"[,"section-class"] ] )
指定配置設定函數的代碼段。code_seg編譯訓示為函數指定預設的段。你也能夠像段名一樣指定一個可選的類名。使用沒有段名字元串的#pragma code_seg将恢複配置設定到編譯開始時候的狀态。
#pragma const_seg( ["section-name"[, "section-class"] ] )
指定用于常量資料的預設段。data_seg編譯訓示除了可以工作于所有資料以外具有一樣的效果。你能夠使用該編譯訓示将你的常量資料儲存在一個隻讀的段中。
#pragma const_seg( "MY_DATA" )
導緻在#pragma語句後面的常量資料配置設定在一個叫做MY_DATA的段中。
用const_seg編譯訓示配置設定的資料不包含任何關于其位置的資訊。
#pragma comment( comment-type [, commentstring] )
将描述記錄安排到目标檔案或可執行檔案中去。comment-type是下面說明的五個預定義辨別符中的一個,用來指定描述記錄的類型。可選的commentstring是一個字元串文字值用于為一些描述類型提供附加的資訊。因為commentstring是一個字元串文字值,是以它遵從字元串文字值的所有規則,例如換碼字元、嵌入的引号(")和聯接。
在目标檔案中放置編譯程式名和版本号。該描述記錄被連接配接程式忽略。如果你為這個記錄類型提供一個commentstring參數,編譯程式将生成一個警告。
将commentstring放置到目标檔案中去。在連結時,這個字元串再被放到可執行檔案去中。當可執行檔案被裝載時這個字元串不會被裝入記憶體,然而,它可以被一個能夠在檔案中搜尋可列印字元串的程式找到。該描述記錄的一個用處是在可執行檔案中嵌入版本号或者類似的資訊。
将一個庫搜尋記錄放置到目标檔案中去。該描述類型必須有包含你要連接配接程式搜尋的庫名(和可能的路徑)的commentstring參數。因為在目标檔案中該庫名先于預設的庫搜尋記錄,是以連接配接程式将如同你在指令行輸入這些庫一樣來搜尋它們。你可以在一個源檔案中放置多個庫搜尋記錄,每個記錄将按照它們出現在源檔案中的順序出現在目标檔案中。
在目标檔案中放置連接配接程式選項。你可以用這個描述類型指定連接配接程式選項來代替在Project Setting對話框中Link頁内的選項。例如,你可以指定/include選項以強迫包含一個符号:
#pragma comment(linker, "/include:__mySymbol")
在目标檔案中包含一個普通描述記錄。commentstring參數包含描述的文本。該描述記錄将被連接配接程式忽略。
下面的編譯訓示導緻連接配接程式在連接配接時搜尋EMAPI.LIB庫。連接配接程式首先在目前工作目錄然後在LIB環境變量指定的路徑中搜尋。
#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 )
注意,對于具有commentstring參數的描述記錄,你可以使用其它用作字元串文字量的宏來提供宏擴充為字元串文字量。你也能夠聯結任何字元串文字量和宏的組合來擴充成為一個字元串文字量。例如,下面的語句是可以接受的:
#pragma comment( user, "Compiled on " __DATE__ " at " __TIME__ )
2010-04-18 14:22:00| 分類: 預設分類 | 标簽: |字号大中小訂閱
8 component
#pragma component( browser, { on | off }[, references [, name ]] )
#pragma component( minrebuild, on | off )
從源檔案内控制浏覽資訊和依賴資訊的收集。
你可以将收集打開或關閉,你也可以指定收集時忽略特别的名字。
使用on或off在編譯訓示以後控制浏覽資訊的收集。例如:
#pragma component(browser, off)
終止編譯程式收集浏覽資訊。
注意,為了用這個編譯訓示打開浏覽資訊的收集,必須先從Project Setting對話框或者指令行允許浏覽資訊。
references選項可以有也可以沒有name參數。使用沒有name參數的references選項将打開或者關閉引用資訊的收集(然而繼續收集其它浏覽資訊)。例如:
#pragma component(browser, off, references)
終止編譯程式收集引用資訊。
使用有name和off參數的references選項将阻止從浏覽資訊視窗中出現引用到的名字。用這個文法将忽略你不感興趣的名字和類型進而減少浏覽資訊檔案的大小。例如:
#pragma component(browser, off, references, DWORD)
從這一點以後忽略DWORD的引用。你能夠用on恢複DWORD的引用收集:
#pragma component(browser, on, references, DWORD)
這是唯一的方法可以恢複收集指定名字的引用,你必須顯式地打開任何你關閉的名字。
為了防止預處理程式擴充名字(就像擴充NULL到0),用引号括起來:
#pragma component(browser, off, references, "NULL")
Visual C++的最小化重建功能要求編譯程式建立并儲存需要大量磁盤空間的C++類依賴資訊。為了節省磁盤空間,你能夠在你不需要收集依賴資訊時使用#pragma component(minrebuild,off),例如,沒有改變過頭檔案。在未修改過的類之後插入#pragma component(minrebuild,on)重新打開依賴資訊。
詳見Enable Minimal Rebuild(/Gm)編譯程式選項。
指定資料的預設段。例如:
#pragma data_seg( "MY_DATA" )
導緻在#pragma語句後配置設定的資料儲存在一個叫做MY_DATA的段中。
用data_seg編譯訓示配置設定的資料不包含任何關于其位置的資訊。
#pragma function( function1 [, function2, ...] )
指定必須生成對編譯訓示中參數清單内函數的調用。如果你使用intrinsic編譯訓示(或者/Oi)來告訴編譯程式生成内含函數(内含函數如同嵌入代碼一樣生成,不作為一個函數調用),你能夠用function編譯訓示顯式地強迫函數調用。當遇到一個function編譯訓示,它将在其後面遇到的第一個包含有内含函數的函數定義處生效。其持續作用到源檔案的尾部或者出現對同一個内含函數指定intrinsic編譯訓示。function編譯訓示隻能用于函數外——在全局層次。
為了列出具有内含形式的函數表,參見#pragma intrinsic。
#pragma hdrstop [( "filename" )]
控制預編譯頭檔案的工作方式。filename是要使用或者建立(依賴于是否指定了/Yu或/Yc)預編譯頭檔案的名字。如果 filename不包括一個指定路徑,将假定預編譯頭檔案和源檔案處于同一個目錄中。當指定自動預編譯頭檔案選項/YX時,所有指定的檔案名将被忽略。
如果有/YX或者/Yc選項,而且C或C++檔案包含了一個hdrstop編譯訓示時,編譯程式儲存編譯訓示之前的編譯狀态。編譯訓示之後的編譯狀态不被儲存。
hdrstop編譯選項不能出現在一個頭檔案内。它隻能出現在源檔案的檔案級,它也不能出現在任何資料或者函數的說明或定義之中。
注意,除非指定沒有檔案名的/YX選項或者/Yu或/Yc選項,否則hdrstop編譯訓示将被忽略。
用一個檔案名命名要儲存編譯狀态的預編譯頭檔案。在hdrstop和filename之間的空格是可選的。在hdrstop編譯訓示中的檔案名是一個字元串,這樣它服從于C或C++的字元串規則。特别的,你必須像下面例子裡面顯示的用引号括起來。
#pragma hdrstop( "c:\projects\include\myinc.pch" )
預編譯頭檔案的檔案名按照如下規則決定,按照優先次序:
/Fp編譯程式選項的參數;
由#pragma hdrstop的filename參數;
原檔案名的基本檔案名加上.PCH擴充名。
#pragma include_alias( "long_filename", "short_filename" )
#pragma include_alias( <long_filename>, <short_filename> )
指定作為long_filename别名的short_filename。一些檔案系統允許超出8.3FAT檔案系統限制的長頭檔案名。編譯程式不能簡單地将長檔案名截斷為8.3名字,因為長頭檔案名的前8個字元可能不是唯一的。無論何時編譯程式遇到long_filename串,它代替short_filename,并且用short_filename搜尋頭檔案。這個編譯訓示必須出現在相應的#include訓示之前。例如:
// First eight characters of these two files not unique.
#pragma include_alias( "AppleSystemHeaderQuickdraw.h", "quickdra.h" )
#pragma include_alias( "AppleSystemHeaderFruit.h", "fruit.h" )
#pragma include_alias( "GraphicsMenu.h", "gramenu.h" )
#include "AppleSystemHeaderQuickdraw.h"
#include "AppleSystemHeaderFruit.h"
#include "GraphicsMenu.h"
這個别名在搜尋時精确比對,包括拼寫和雙引号、尖括号。include_alias編譯訓示在檔案名上執行簡單的字元串比對,不進行其它的檔案名驗證。例如,給出下列訓示:
#pragma include_alias("mymath.h", "math.h")
#include "./mymath.h"
#include "sys/mymath.h"
并不執行别名替代,因為頭檔案名字元串沒有精确比對。另外,在/Yu,/Yc和/YX編譯程式選項,或hdrstop編譯訓示中作為參數的頭檔案名不被替換。例如,如果你的源檔案包含下列訓示:
#include <AppleSystemHeaderStop.h>
相應的編譯程式選項必須是:
/YcAppleSystemHeaderStop.h
你能夠用include_alias編譯訓示将任何頭檔案映射到其它檔案。例如:
#pragma include_alias( "api.h", "c:\version1.0\api.h" )
#pragma include_alias( <stdio.h>, <newstdio.h> )
#include "api.h"
#include <stdio.h>
不要混淆用雙引号和尖括号括起來的檔案名。例如,給出上面的#pragma include_alias訓示時,在下面的#include訓示中編譯程式不執行替換。
#include <api.h>
#include "stdio.h"
還有,下面的訓示将産生一個錯誤:
#pragma include_alias(<header.h>, "header.h") // Error
注意,在錯誤資訊中報告的檔案名,或者預定義宏__FILE__的值,是執行替換以後的檔案名。例如,在下列訓示之後:
#pragma include_alias( "VeryLongFileName.H", "myfile.h" )
#include "VeryLongFileName.H"
檔案VeryLongFileName.H産生下列錯誤資訊:
myfile.h(15) : error C2059 : syntax error
還要注意的是不支援傳遞性。給出下面的訓示:
#pragma include_alias( "one.h", "two.h" )
#pragma include_alias( "two.h", "three.h" )
#include "one.h"
編譯程式将搜尋two.h而不是three.h。
C++特有
#pragma init_seg({ compiler | lib | user | "section-name" [, "func-name"]} )
指定影響啟動代碼執行的關鍵字或代碼段。因為全局靜态對象的初始化可以包含執行代碼,是以你必須指定一個關鍵字來定義什麼時候構造對象。在使用需要初始化的動态連接配接庫(DLL)或程式庫時使用init_seg編譯訓示是尤其重要的。
init_seg編譯訓示的選項有:
由Microsoft C運作時間庫保留。在這個組中的對象将第一個構造。
用于第三方類庫開發者的初始化。在這個組中的對象将在标記為構造compiler的對象之後,其它對象之前構造。
用于任何其它使用者。在這個組中的對象将最後構造。
允許顯式地指定初始化段。在使用者指定的section-name中的對象将不會隐式地構造,而它們的位址将會被放置在由section-name命名的段中。
指定當程式退出時,作為atexit函數調用的函數。這個函數必須具有和atexit函數相同的形式:
int funcname(void (__cdecl *)(void));
如果你需要延遲初始化,你能夠選擇指定顯式的段名。随後你必須調用每個靜态對象的構造函數。
#pragma inline_depth( [0... 255] )
通過控制能夠被擴充的一系列函數調用(從0到255次)來控制嵌入函數擴充的發生次數,這個編譯訓示控制用inline,__inline标記的或在/Ob2選項下能自動嵌入的嵌入函數。
inline_depth編譯訓示控制能夠被擴充的一系列函數調用。例如,如果嵌入深度是4,并且如果A調用B然後調用C,所有的3次調用都将做嵌入擴充。然而,如果設定的最近一次嵌入深度是2,則隻有A和B被擴充,而C仍然作為函數調用。
為了使用這個編譯訓示,你必須設定編譯程式選項/Ob為1或者2。用這個編譯訓示指定的深度設定在該訓示後面的第一個函數開始生效。如果你在括号内不指定一個值,inline_depth設定嵌入深度到預設值8。
在擴充時,嵌入深度可以被減少而不能被增加。如果嵌入深度是6,同時在擴充過程中預處理程式遇到一個inline_depth編譯訓示設定為8,則深度保持為6。
嵌入深度0将拒絕嵌入擴充,深度255将設定在嵌入擴充時沒有限制。如果用一個沒有指定值的編譯訓示,則使用為預設值。
#pragma inline_recursion( [{on | off}] )
控制直接或者互相間的遞歸函數調用式的嵌入擴充。用這個編譯訓示控制用inline,__inline标記的或在/Ob2選項下能自動嵌入的嵌入函數。使用這個編譯訓示需要設定編譯程式選項/Ob為1或者2。預設的inline_recursion狀态是off。這個編譯訓示在出現該編譯訓示之後第一個函數調用起作用,并不影響函數的定義。
inline_recursion編譯訓示控制如何擴充遞歸函數。如果inline_recursion是off,并且如果一個嵌入函數調用了它自己(直接的或者間接的),函數将僅僅擴充一次。如果inline_recursion是on,函數将擴充多次直到達到inline_depth的值或者容量限制。
#pragma intrinsic( function1 [, function2, ...] )
指定對在編譯訓示參數表中函數調用是内含的。編譯程式像嵌入代碼一樣生成内含函數,而不是函數調用。下面列出了具有内含形式的庫函數。一旦遇到intrinsic編譯訓示,它從第一個包含指定内含函數的函數定義開始起作用。作用持續到源檔案尾部或者出現包含相同内含函數的function編譯訓示。intrinsic編譯訓示隻能用在函數定義外——在全局層次。
下列函數具有内含形式:
_disable
_enable
_inp
_inpw
_lrotl
_lrotr
_outp
_outpw
_rotl
_rotr
_strset
abs
fabs
labs
memcmp
memcpy
memset
strcat
strcmp
strcpy
strlen
使用内含函數的程式更快,因為它們沒有函數調用的額外代價,然而因為有附加的代碼生成,可能比較大。
注意,_alloca和setjmp函數總是内含的,這個行為不受intrinsic編譯訓示影響。
下列浮點函數沒有内含形式。然而它們具有直接将參數通過浮點晶片傳送而不是推入程式堆棧的版本。
acos
asin
cosh
fmod
pow
sinh
tanh
當你同時指定/Oi和/Og編譯程式選項(或者任何包含/Og,/Ox,/O1和/O2的選項)時下列浮點函數具有真正的内含形式。
atan
exp
log10
sqrt
atan2
log
sin
tan
cos
你可以用編譯程式選項/Op或/Za來覆寫真内含浮點選項的生成。在這種情況下,函數會像一般庫函數一樣被生成,同時直接将參數通過浮點晶片傳送而不是推入程式堆棧。
#pragma message( messagestring )
不中斷編譯,發送一個字元串文字量到标準輸出。message編譯訓示的典型運用是在編譯時顯示資訊。
下面的代碼段用message編譯訓示在編譯過程中顯示一條資訊:
#if _M_IX86 == 500
#pragma message( "Pentium processor build" )
#endif
messagestring參數可以是一個能夠擴充成字元串文字量的宏,并且你能夠用字元串文字量和宏的任何組合來構造。例如,下面的語句顯示被編譯檔案的檔案名和檔案最後一次修改的日期和時間。
#pragma message( "Compiling " __FILE__ )
#pragma message( "Last modified on " __TIMESTAMP__ )
#pragma once
指定在建立過程中該編譯訓示所在的檔案僅僅被編譯程式包含(打開)一次。該編譯訓示的一種常見用法如下:
//header.h
// Your C or C++ code would follow:
僅在專業版和企業版中存在
#pragma optimize( "[optimization-list]", {on | off} )
代碼優化僅有Visual C++專業版和企業版支援。詳見Visual C++ Edition。
指定在函數層次執行的優化。optimize編譯選項必須在函數外出現,并且在該編譯訓示出現以後的第一個函數定義開始起作用。on和off參數打開或關閉在optimization-list指定的選項。
optimization-list能夠是0或更多個在表2.2中給出的參數:
表 2.2 optimize編譯訓示的參數
參數
優化類型
a
假定沒有别名。
g
允許全局優化。
p
增強浮點一緻性。
s 或 t
指定更短或者更快的機器代碼序列。
w
假定在函數調用中沒有别名。
y
在程式堆棧中生成架構指針。
這些和在/O編譯程式選項中使用的是相同的字母。例如:
#pragma optimize( "atp", on )
用空字元串("")的optimize編譯訓示是一種特别形式。它要麼關閉所有的優化選項,要麼恢複它們到原始(或預設)的設定。
#pragma optimize( "", off )
.
#pragma optimize( "", on )
#pragma pack( [ n] )
指定結構和聯合成員的緊縮對齊。盡管用/Zp選項設定整個翻譯單元的結構和聯合成員的緊縮對齊,可以用pack編譯訓示在資料說明層次設定緊縮對齊。從出現該編譯訓示後的第一個結構或者聯合說明開始生效。這個編譯訓示不影響定義。
當你使用#pragma pack(n),其中n是1,2,4,8或者16,第一個以後的每個結構成員儲存在較小的成員類型或者n位元組邊界上。如果你使用沒有參數的#pragma pack,結構成員将被緊縮到由/Zp指定的值。預設的/Zp緊縮的大小是/Zp8。
編譯程式還支援下面的增強文法:
#pragma pack( [ [ { push | pop}, ] [ identifier, ] ] [ n ] )
該文法允許你将使用不同緊縮編譯訓示的元件合并到同一個翻譯單元内。
每次出現有push參數的pack編譯訓示将儲存目前的緊縮對齊值到一個内部的編譯程式堆棧。編譯訓示的參數清單從左向右讀取。如果你使用了push,目前緊縮值被儲存。如果你提供了一個n值,這個值将成為新的緊縮值。如果你指定了一個你標明的标示符,這個标示符将和新的緊縮值關聯。
每次出現有pop參數的pack編譯訓示從内部編譯程式堆棧頂部取出一個值并将那個值作為新的緊縮對齊。如果你用了pop,而内部編譯程式堆棧是空的,對齊值将從指令行得到,同時給出一個警告。如果你用了pop并指定了n的值,那個值将成為新的緊縮值。如果你用了pop并指定了一個标示符,将移去所有儲存在堆棧中的的值直到比對的找到比對的标示符,和該标示符關聯的緊縮值也被從堆棧中移出來成為新的緊縮值。如果沒有找到比對的标示符,将從指令行擷取緊縮值并産生一個1級警告。預設的緊縮對齊是8。
pack編譯訓示的新的增強功能允許你編寫頭檔案保證在使用頭檔案之前和其後的緊縮值是一樣的:
#pragma pack( push, enter_include1 )
#pragma pack( pop, enter_include1 )
在前面的例子中,進入頭檔案時将目前緊縮值和标示符enter_include1關聯并推入,被記住。在頭檔案尾部的pack編譯選項移去所有在頭檔案中可能遇到的緊縮值并移去和enter_include1關聯的緊縮值。這樣頭檔案保證了在使用頭檔案之前和其後的緊縮值是一樣的。
新功能也允許你在你的代碼内用pack編譯訓示為不同的代碼,例如頭檔案設定不同的緊縮對齊。
#pragma pack( push, before_include1 )
#include "include1.h"
#pragma pack( pop, before_include1 )
在上一個例子中,你的代碼受到保護,防止了在include.h中的任何緊縮值的改變。
#pragma warning( warning-specifier : warning-number-list [,warning-specifier : warning-number-list...] )
#pragma warning( push[ , n ] )
#pragma warning( pop )
允許有選擇地修改編譯程式警告資訊的行為。
warning-specifier能夠是下列值之一:
warning-specifier
含義
隻顯示指定資訊一次。
default
對指定資訊應用預設的編譯程式選項。
1,2,3,4
對指定資訊引用給定的警告等級。
disable
不顯示指定資訊。
error
對指定資訊作為錯誤顯示。
warning-number_list能夠包含任何警告編号。如下,在一個編譯訓示中可以指定多個選項:
#pragma warning( disable : 4507 34; once : 4385; error : 164 )
這等價于:
#pragma warning( disable : 4507 34 ) // Disable warning messages
// 4507 and 34.
#pragma warning( once : 4385 ) // Issue warning 4385
// only once.
#pragma warning( error : 164 ) // Report warning 164
// as an error.
對于那些關于代碼生成的,大于4699的警告标号,warning編譯訓示僅在函數定義外時有效。如果指定的警告編号大于4699并且用于函數内時被忽略。下面例子說明了用warning編譯訓示禁止、然後恢複有關代碼生成警告資訊的正确位置:
int a;
#pragma warning( disable : 4705 )
void func()
{
a;
}
#pragma warning( default : 4705 )
warning編譯訓示也支援下面文法:
#pragma warning( push [ ,n ] )
這裡n表示警告等級(1到4)。
warning(push)編譯訓示儲存所有警告的目前警告狀态。warning(push,n)儲存所有警告的目前狀态并将全局警告等級設定為n。
warning(pop)彈出最後一次推入堆棧中的警告狀态。任何在push和pop之間改變的警告狀态将被取消。考慮下面的例子:
#pragma warning( push )
#pragma warning( disable : 4706 )
#pragma warning( disable : 4707 )
// Some code
在這些代碼的結束,pop恢複了所有警告的狀态(包括4705,4706和4707)到代碼開始時候的樣子。
當你編寫頭檔案時,你能用push和pop來保證任何使用者修改的警告狀态不會影響正常編譯你的頭檔案。在頭檔案開始的地方使用push,在結束地方使用pop。例如,假定你有一個不能順利在4級警告下編譯的頭檔案,下面的代碼改變警告等級到3,然後在頭檔案的結束時恢複到原來的警告等級。
#pragma warning( push, 3 )
// Declarations/ definitions
2010-04-18 14:21:00| 分類: 預設分類 | 标簽: |字号大中小訂閱