1. 程式人生 > >編譯指令#pragma詳解

編譯指令#pragma詳解

編譯指令#pragma詳解

With #pragma, C++Builder can define the directives it wants without interfering with other compilers that support #pragma. If the compiler doesn't recognize directive-name, it ignores the #pragma directive without any error or warning message.

C++Builder supports the following #pragma directives:

#pragma alignment
#pragma anon_struct
#pragma argsused
#pragma checkoption
#pragma codeseg
#pragma comment
#pragma defineonoption
#pragma exit
#pragma hdrfile
#pragma hdrstop
#pragma inline
#pragma intrinsic
#pragma link
#pragma message
#pragma nopushoptwarn
#pragma obsolete
#pragma option
#pragma pack
#pragma package
#pragma resource
#pragma startup
#pragma undefineonoption
#pragma warn

#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(...)

    該指令將一個註釋記錄放入一個物件檔案或可執行檔案中。 

    #pragma comment(comment-type,["commentstring"]) 

comment-type是一個預定義的識別符號,指定註釋的型別,應該是compiler,exestr,lib,linker之一。 comment string是一個提供為comment-type提供附加資訊的字串。


常用的lib關鍵字,可以幫我們連入一個庫檔案。如:
    #pragma  comment(lib, "comctl32.lib")
    #pragma  comment(lib, "vfw32.lib")
    #pragma  comment(lib, "wsock32.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++編譯程式。

1  alloc_text

#pragma alloc_text( "textsection", function1, ... ) 命名特別定義的函式駐留的程式碼段。該編譯指示必須出現在函式說明符和函式定義之間。 alloc_text編譯指示不處理C++成員函式或過載函式。它僅能應用在以C連線方式說明的函式——就是說,函式是用extern "C"連線指示符說明的。如果你試圖將這個編譯指示應用於一個具有C++連線方式的函式時,將出現一個編譯程式錯誤。 由於不支援使用__based的函式地址,需要使用alloc_text編譯指示來指定段位置。由textsection指定的名字應該由雙引號括起來。 alloc_text編譯指示必須出現在任何需要指定的函式說明之後,以及這些函式的定義之前。 alloc_text編譯指示中引用的函式必須和該編譯指示處於同一個模組中。如果不這樣做,使以後一個未定義的函式被編譯到一個不同的程式碼段時,錯誤會也可能不會被捕獲。即使程式一般會正常執行,但是函式不會分派到應該在的段。 alloc_text的其它限制如下: 它不能用在一個函式內部。 它必須用於函式說明以後,函式定義以前。

2  auto_inline

#pragma auto_inline( [{on | off}] ) 當指定off時將任何一個可以被考慮為作為自動嵌入擴充套件候選的函式排除出該範圍。為了使用auto_inline編譯指示,將其緊接著寫在一個函式定義之前或之後(不是在其內部)。該編譯指示將在其出現以後的第一個函式定義開始起作用。auto_inline編譯指示對顯式的inline函式不起作用。

3  bss_seg

#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++的,現在將忽略它。

4  check_stack

#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()或#pragma check_stack 後續的函式開啟堆疊檢查
#pragma check_stack(on)或#pragma check_stack(+) 是或者否 後續的函式開啟堆疊檢查
#pragma check_stack(off)或#pragma check_stack(-) 是或者否 後續的函式關閉堆疊檢查

5  code_seg

#pragma code_seg( ["section-name"[,"section-class"] ] ) 指定分配函式的程式碼段。code_seg編譯指示為函式指定預設的段。你也能夠像段名一樣指定一個可選的類名。使用沒有段名字串的#pragma code_seg將恢復分配到編譯開始時候的狀態。

6  const_seg

#pragma const_seg( ["section-name"[, "section-class"] ] ) 指定用於常量資料的預設段。data_seg編譯指示除了可以工作於所有資料以外具有一樣的效果。你能夠使用該編譯指示將你的常量資料儲存在一個只讀的段中。 #pragma const_seg( "MY_DATA" ) 導致在#pragma語句後面的常量資料分配在一個叫做MY_DATA的段中。 用const_seg編譯指示分配的資料不包含任何關於其位置的資訊。 第二個引數section-class是用於相容2.0版本以前的Visual C++的,現在將忽略它。

7  comment

#pragma comment( comment-type [, commentstring] ) 將描述記錄安排到目標檔案或可執行檔案中去。comment-type是下面說明的五個預定義識別符號中的一個,用來指定描述記錄的型別。可選的commentstring是一個字串文字值用於為一些描述型別提供附加的資訊。因為commentstring是一個字串文字值,所以它遵從字串文字值的所有規則,例如換碼字元、嵌入的引號(")和聯接。

7-1  compiler

在目標檔案中放置編譯程式名和版本號。該描述記錄被連線程式忽略。如果你為這個記錄型別提供一個commentstring引數,編譯程式將生成一個警告。

7-2  exestr

將commentstring放置到目標檔案中去。在連結時,這個字串再被放到可執行檔案去中。當可執行檔案被裝載時這個字串不會被裝入記憶體,然而,它可以被一個能夠在檔案中搜索可列印字串的程式找到。該描述記錄的一個用處是在可執行檔案中嵌入版本號或者類似的資訊。

7-3  lib

將一個庫搜尋記錄放置到目標檔案中去。該描述型別必須有包含你要連線程式搜尋的庫名(和可能的路徑)的commentstring引數。因為在目標檔案中該庫名先於預設的庫搜尋記錄,所以連線程式將如同你在命令列輸入這些庫一樣來搜尋它們。你可以在一個原始檔中放置多個庫搜尋記錄,每個記錄將按照它們出現在原始檔中的順序出現在目標檔案中。

7-4  linker

在目標檔案中放置連線程式選項。你可以用這個描述型別指定連線程式選項來代替在Project Setting對話方塊中Link頁內的選項。例如,你可以指定/include選項以強迫包含一個符號: #pragma comment(linker, "/include:__mySymbol")

7-5  user

在目標檔案中包含一個普通描述記錄。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__ )

8  component

#pragma component( browser, { on | off }[, references [, name ]] ) #pragma component( minrebuild, on | off )   從原始檔內控制瀏覽資訊和依賴資訊的收集。

8-1  瀏覽資訊(Browser

你可以將收集開啟或關閉,你也可以指定收集時忽略特別的名字。 使用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")

8-2  最小化重建(Minimal Rebuild

Visual C++的最小化重建功能要求編譯程式建立並儲存需要大量磁碟空間的C++類依賴資訊。為了節省磁碟空間,你能夠在你不需要收集依賴資訊時使用#pragma component(minrebuild,off),例如,沒有改變過標頭檔案。在未修改過的類之後插入#pragma component(minrebuild,on)重新開啟依賴資訊。 詳見Enable Minimal Rebuild(/Gm)編譯程式選項。

9  data_seg

#pragma data_seg( ["section-name"[, "section-class"] ] ) 指定資料的預設段。例如: #pragma data_seg( "MY_DATA" ) 導致在#pragma語句後分配的資料儲存在一個叫做MY_DATA的段中。 用data_seg編譯指示分配的資料不包含任何關於其位置的資訊。 第二個引數section-class是用於相容2.0版本以前的Visual C++的,現在將忽略它。

10  function

#pragma function( function1 [, function2, ...] ) 指定必須生成對編譯指示中引數列表內函式的呼叫。如果你使用intrinsic編譯指示(或者/Oi)來告訴編譯程式生成內含函式(內含函式如同嵌入程式碼一樣生成,不作為一個函式呼叫),你能夠用function編譯指示顯式地強迫函式呼叫。當遇到一個function編譯指示,它將在其後面遇到的第一個包含有內含函式的函式定義處生效。其持續作用到原始檔的尾部或者出現對同一個內含函式指定intrinsic編譯指示。function編譯指示只能用於函式外——在全域性層次。 為了列出具有內含形式的函式表,參見#pragma intrinsic。

11  hdrstop

#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副檔名。

12  include_alias

#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。

13  init_seg

C++特有 #pragma init_seg({ compiler | lib | user | "section-name" [, "func-name"]} ) 指定影響啟動程式碼執行的關鍵字或程式碼段。因為全域性靜態物件的初始化可以包含執行程式碼,所以你必須指定一個關鍵字來定義什麼時候構造物件。在使用需要初始化的動態連線庫(DLL)或程式庫時使用init_seg編譯指示是尤其重要的。 init_seg編譯指示的選項有:

13-1  compiler

由Microsoft C執行時間庫保留。在這個組中的物件將第一個構造。

13-2  lib

用於第三方類庫開發者的初始化。在這個組中的物件將在標記為構造compiler的物件之後,其它物件之前構造。

13-3  user

用於任何其它使用者。在這個組中的物件將最後構造。

13-4  section-name

允許顯式地指定初始化段。在使用者指定的section-name中的物件將不會隱式地構造,而它們的地址將會被放置在由section-name命名的段中。

13-5  func-name

指定當程式退出時,作為atexit函式呼叫的函式。這個函式必須具有和atexit函式相同的形式: int funcname(void (__cdecl *)(void)); 如果你需要延遲初始化,你能夠選擇指定顯式的段名。隨後你必須呼叫每個靜態物件的建構函式。

14  inline_depth

#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將設定在嵌入擴充套件時沒有限制。如果用一個沒有指定值的編譯指示,則使用為預設值。

15  inline_recursion

#pragma inline_recursion( [{on | off}] ) 控制直接或者相互間的遞迴函式呼叫式的嵌入擴充套件。用這個編譯指示控制用inline,__inline標記的或在/Ob2選項下能自動嵌入的嵌入函式。使用這個編譯指示需要設定編譯程式選項/Ob為1或者2。預設的inline_recursion狀態是off。這個編譯指示在出現該編譯指示之後第一個函式呼叫起作用,並不影響函式的定義。 inline_recursion編譯指示控制如何擴充套件遞迴函式。如果inline_recursion是off,並且如果一個嵌入函式呼叫了它自己(直接的或者間接的),函式將僅僅擴充套件一次。如果inline_recursion是on,函式將擴充套件多次直到達到inline_depth的值或者容量限制。

16  intrinsic

#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來覆蓋真內含浮點選項的生成。在這種情況下,函式會像一般庫函式一樣被生成,同時直接將引數通過浮點晶片傳送而不是推入程式堆疊。

17  message

#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__ )

18  once

#pragma once 指定在建立過程中該編譯指示所在的檔案僅僅被編譯程式包含(開啟)一次。該編譯指示的一種常見用法如下: //header.h #pragma once // Your C or C++ code would follow:

19  optimize

僅在專業版和企業版中存在 #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 )

20  pack

#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編譯指示的新的增強功能允許你編寫標頭檔案保證在使用標頭檔案之前和其後的緊縮值是一樣的: /* File name: include1.h */ <