預編譯和預處理以及編譯選項的控制

  

一 預編譯:程序員

爲了增長編譯速度每每要提早對一些頭文件及代碼進行編譯,而後給後面正式編譯時使用,以節省開銷。這些文件代碼基本上不會更改,好比MFC的一些頭文件以及一些必要的API使用代碼,固然,你也能夠把你本身的一部分代碼封裝起來到一個C或C++文件中,(好比在其中包含一些頭文件或必要的代碼什麼的,而後在VC-C/C++--PreCompiled Headers裏選擇第三項Create compiled Header file)來指定爲預編譯頭文件,這樣就在之後的程序修改中編譯時不會反覆編譯這部分。固然過多的使用預編譯頭文件會大大下降編譯的速度,因此可使用下面的預處理指令:算法

#pragma hdrstop表示預編譯頭文件到此爲止,後面的頭文件不進行預編譯。BCB能夠預編譯頭文件以加快連接的速度,但若是全部頭文件都進行預編譯又可能佔太多磁盤空間,因此使用這個選項排除一些頭文件。
有時單元之間有依賴關係,好比單元A依賴單元B,因此單元B要先於單元A編譯。你能夠用#pragma startup指定編譯優先級,若是使用了#pragma package(smart_init) ,BCB就會根據優先級的大小前後編譯。
編程

舉例:主要是轉別人的博文,感謝。api

今天在改一個很大的程序,慢慢看,慢慢改。忽然發現一個.c文件,裏面什麼也沒有,數組

就幾個頭文件,我一看,我靠,這不是把簡單的問題搞複雜了嗎,隨手刪掉那個c文件。安全

結果不能編譯了,我靠:網絡

fatal error C1083: Cannot open precompiled header file: \'Debug/v13_3.pch\':框架

No such file or directoryide

怎麼rebuild all都不行。模塊化

上網查了一下,才搞懂了:

----------------總結------

若是工程很大,頭文件不少,而有幾個頭文件又是常常要用的,那麼

1。把這些頭文件所有寫到一個頭文件裏面去,好比寫到preh.h

2。寫一個preh.c,裏面只一句話:#include "preh.h"

3。對於preh.c,在project setting裏面設置creat precompiled headers,對於其餘

.c文件,設置use precompiled header file

//

哈哈

我試了一下,效果很明顯,不用precompiled header,編譯一次我能夠去上個廁所,用

precompiled header,編譯的時候,我能夠站起來伸個懶腰,活動活動就差很少啦

---------轉載的文章----------

預編譯頭的概念:

所謂的預編譯頭就是把一個工程中的那一部分代碼,預先編譯好放在一個文件裏(一般是

以.pch爲擴展名的),這個文件就稱爲預編譯頭文件這些預先編譯好的代碼能夠是任何的

C/C++代碼--------甚至是inline的函數,可是必須是穩定的,在工程開發的過程當中不會

被常常改變。若是這些代碼被修改,則須要從新編譯生成預編譯頭文件。注意生成預編

譯頭文件是很耗時間的。同時你得注意預編譯頭文件一般很大,一般有6-7M大。注意及

時清理那些沒有用的預編譯頭文件。

也許你會問:如今的編譯器都有Time stamp的功能,編譯器在編譯整個工程的時候,它

只會編譯那些通過修改的文件,而不會去編譯那些從上次編譯過,到如今沒有被修改過

的文件。那麼爲何還要預編譯頭文件呢?答案在這裏,咱們知道編譯器是以文件爲單

位編譯的,一個文件通過修改後,會從新編譯整個文件,固然在這個文件裏包含的全部

頭文件中的東西(.eg Macro, Preprocesser )都要從新處理一遍。VC的預編譯頭文件

保存的正是這部分信息。以免每次都要從新處理這些頭文件。

預編譯頭的做用:

根據上文介紹,預編譯頭文件的做用固然就是提升便宜速度了,有了它你沒有必要每次

都編譯那些不須要常常改變的代碼。編譯性能固然就提升了。

預編譯頭的使用:

要使用預編譯頭,咱們必須指定一個頭文件,這個頭文件包含咱們不會常常改變的

代碼和其餘的頭文件,而後咱們用這個頭文件來生成一個預編譯頭文件(.pch文件)

想必你們都知道 StdAfx.h這個文件。不少人都認爲這是VC提供的一個「系統級別」的

,編譯器帶的一個頭文件。其實不是的,這個文件能夠是任何名字的。咱們來考察一個

典型的由AppWizard生成的MFC Dialog Based 程序的預編譯頭文件。(由於AppWizard

會爲咱們指定好如何使用預編譯頭文件,默認的是StdAfx.h,這是VC起的名字)。咱們

會發現這個頭文件裏包含了如下的頭文件:

#include <afxwin.h> // MFC core and standard components

#include <afxext.h> // MFC extensions

#include <afxdisp.h> // MFC Automation classes

#include <afxdtctl.h> // MFC support for Internet Explorer 4

Common Controls

#include <afxcmn.h>

這些正是使用MFC的必須包含的頭文件,固然咱們不太可能在咱們的工程中修改這些頭文

件的,因此說他們是穩定的。

那麼咱們如何指定它來生成預編譯頭文件。咱們知道一個頭文件是不能編譯的。因此我

們還須要一個cpp文件來生成.pch 文件。這個文件默認的就是StdAfx.cpp。在這個文件

裏只有一句代碼就是:#include 「Stdafx.h」。緣由是理所固然的,咱們僅僅是要它能

夠編譯而已?D?D?D也就是說,要的只是它的.cpp的擴展名。咱們能夠用/Yc編譯開關來指

定StdAfx.cpp來生成一個.pch文件,經過/Fp編譯開關來指定生成的pch文件的名字。打

開project ->Setting->C/C++ 對話框。把Category指向Precompiled Header。在左邊的

樹形視圖裏選擇整個工程 

Project Options(右下角的那個白的地方)能夠看到 /Fp 「debug/PCH.pch」,這就是指

定生成的.pch文件的名字,默認的一般是 <工程名>.pch(個人示例工程名就是PCH)。

而後,在左邊的樹形視圖裏選擇StdAfx.cpp.//這時只能選一個cpp文件!

這時原來的Project Option變成了 Source File Option(原來是工程,如今是一個文件

,固然變了)。在這裏咱們能夠看到 /Yc開關,/Yc的做用就是指定這個文件來建立一個

Pch文件。/Yc後面的文件名是那個包含了穩定代碼的頭文件,一個工程裏只能有一個文

件的能夠有YC開關。VC就根據這個選項把 StdAfx.cpp編譯成一個Obj文件和一個PCH文件

而後咱們再選擇一個其它的文件來看看,//其餘cpp文件

在這裏,Precomplier 選擇了 Use ???一項,頭文件是咱們指定建立PCH 文件的stda

fx.h

文件。事實上,這裏是使用工程裏的設置,(如圖1)/Yu」stdafx.h」。

這樣,咱們就設置好了預編譯頭文件。也就是說,咱們可使用預編譯頭功能了。以

下是注意事項:

1):若是使用了/Yu,就是說使用了預編譯,咱們在每一個.cpp文件的最開頭,我強調一遍

是最開頭,包含 你指定產生pch文件的.h文件(默認是stdafx.h)否則就會有問題。如

果你沒有包含這個文件,就告訴你Unexpected file end. 若是你不是在最開頭包含的,

你本身試如下就知道了,絕對有很驚人的效果?..

fatal error C1010: unexpected end of file while looking for precompiled

header directive

Generating Code...

2)若是你把pch文件不當心丟了,編譯的時候就會產生不少的不正常的行爲。根據以上

的分析,你只要讓編譯器生成一個pch文件。也就是說把 stdafx.cpp(即指定/Yc的那個

cpp文件)重新編譯一遍。固然你能夠傻傻的 Rebuild All。簡單一點就是選擇那個cpp

文件,按一下Ctrl + F7就能夠了。否則但是很浪費時間的哦。

二 預處理

預處理指令中#PRAGMA是用得最多的,最複雜。因此直接拷別人總結的:

pragma comment的使用
該宏放置一個註釋到對象文件或者可執行文件。

#pragma comment( comment-type [,"commentstring"] )comment-type是一個預約義的標識符,指定註釋的類型,應該是compiler,exestr,lib,linker之一。commentstring是一個提供爲comment-type提供附加信息的字符串,
Remarks:
一、compiler:放置編譯器的版本或者名字到一個對象文件,該選項是被linker忽略的。
二、exestr:在之後的版本將被取消。
三、lib:放置一個庫搜索記錄到對象文件中,這個類型應該是和commentstring(指定你要Liner搜索的lib的名稱和路徑)這個庫的名字放在Object文件的默認庫搜索記錄的後面,linker搜索這個這個庫就像你在命令行輸入這個命令同樣。你能夠在一個源文件中設置多個庫記錄,它們在object文件中的順序和在源文件中的順序同樣。若是默認庫和附加庫的次序是須要區別的,使用Z編譯開關是防止默認庫放到object模塊。四、linker:指定一個鏈接選項,這樣就不用在命令行輸入或者在開發環境中設置了。只有下面的linker選項能被傳給Linker.
/DEFAULTLIB

/EXPORT

/INCLUDE

/MANIFESTDEPENDENCY

/MERGE

/SECTION

(1)/DEFAULTLIB:library/DEFAULTLIB 選項將一個 library 添加到 LINK 在解析引用時搜索的庫列表。用 /DEFAULTLIB
指定的庫在命令行上指定的庫以後和 .obj 文件中指定的默認庫以前被搜索。
忽略全部默認庫 (/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 工具獲取該標識符的修飾名形式。

(3)/INCLUDE:symbol
/INCLUDE 選項通知連接器將指定的符號添加到符號表。

若要指定多個符號,請在符號名稱之間鍵入逗號 (,)、分號 (;) 或空格。在命令行上,對每一個符號指定一次 /INCLUDE:symbol。
連接器經過將包含符號定義的對象添加到程序來解析 symbol。該功能對於添包含不會連接到程序的庫對象很是有用。用該選項指定符號將經過 /OPT:REF 重寫該符號的移除。

咱們常常用到的是#pragma   comment(lib,"*.lib")這類的。#pragma   comment(lib,"Ws2_32.lib")表示連接Ws2_32.lib這個庫。   和在工程設置裏寫上鍊入Ws2_32.lib的效果同樣,不過這種方法寫的   程序別人在使用你的代碼的時候就不用再設置工程settings了

 

 

 

 


#pragma C++
解析#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 co
de_seg( ["section-name"[,"section-class"] ] )
它可以設置程序中函數代碼存放的代碼段,當咱們開發驅動程序的時候就會使用到它。

(3)#pragma once (比較經常使用)
只要在頭文件的最開始加入這條指令就可以保證頭文件被編譯一次,這條指令實際上在VC6中就已經有了,可是考慮到兼容性並無太多的使用它。

(4)#pragma hdrstop表示預編譯頭文件到此爲止,後面的頭文件不進行預編譯。BCB能夠預編譯頭文件以加快連接的速度,但若是全部頭文件都進行預編譯又可能佔太多磁盤空間,因此使用這個選項排除一些頭文件。
有時單元之間有依賴關係,好比單元A依賴單元B,因此單元B要先於單元A編譯。你能夠用#pragma 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(on
ce: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()
咱們知道在VC中,對於想結構體Struct這樣的類型,VC採用8字節對齊的方式,若是咱們不想使用8字節對齊(在網絡變成中常常須要這樣),咱們能夠在結構體前面加上
#pragma pack(1)
struct
{
......
}
#pragma pack( )

如下是另外一個轉載:

在vc6的時代頭文件通常使用ifndef define endif
在vc7的時代頭文件通常成了pragma on
ce
不知道有沒有人深究其中的意義
爲何有這樣的代碼,是爲了頭文件不被重複引用,那樣編譯器抱錯的,這兩種方法都是一樣的目的,有沒有區別呢?
仍是舉例來講明,可能有好幾個庫,每一個庫內部可能都有public.h這個文件,若是使用
ifndef public_h
define public_h
...
endif
那麼當一個文件同時引用兩個這樣的庫時,後一個庫裏的文件就不被編譯了,而pragma on
ce能夠保證文件只被編譯一次
看起來pragma on
ce比ifndef define endif要好,那麼ifndef define endif
的地方都pragma on
ce好了。今天碰到了又一個例子,好比你有一個zlib.h在幾個庫都用到,而爲了方便,把zlib每一個目錄下copy了一分,由於這個文件不會做修改,已經很完整了,這個時候若是使用pragma once,就會重複定義,看來ifndef define endif仍是又派上用場的地方。
因此對於公有或者接口的文件,使用ifndef define endif,對於內部的文件使用pragma on
ce.

#pragma once 與 #ifndef #define #endif 的區別

對於#pragma once,根據MSDN解說,可以防止一個文件被屢次包含。與#ifndef #define #endif形式的文件保護相比,前者是平臺相關的,可移植性比較差,可是它效率更高,由於它不須要去打開包含的文件,就能夠判斷這個文件有沒有被包含。固然這個工做是系統幫咱們完成的。
後者的優勢在於它是語言相關的特性,因此可移植性好。可是在包含一個文件的時候,只有打開這個文件,根據文件的保護宏是否已經被定義來判斷此文件是否已經被包含過。效率相對較低。固然在#i nclude的時候,程序員也能夠本身判斷所要包含的文件的保護宏是否已經被定義,來決定是否要包含這個文件。相似下面的代碼:
#ifndef FILE_H_#i nclude "file.h"#endif這樣做能夠獲得較高的效率,並且保證可移植性。可是文件之間的依賴性較高,若是一個文件的保護宏改變的話,全部使用如上形式包含這個文件的文件都要修改。有悖於模塊化的思想。


#pragma da
ta_seg用法總結 (2008-09-05 12:54:54)
標籤:雜談   分類:編程

    Windows在一個Win32程序的地址空間周圍築了一道牆。一般,一個程序的地址空間中的數據是私有的,對別的程序而言是不可見的。可是執行STRPROG的多個執行實體表示了STRLIB在程序的全部執行實體之間共享數據是毫無問題的。當您在一個STRPROG窗口中增長或者刪除一個字符串時,這種改變將當即反映在其它的窗口中。

在所有例程之間,STRLIB共享兩個變量:一個字符數組和一個整數(記錄已儲存的有效字符串的個數)。STRLIB將這兩個變量儲存在共享的一個特殊內存區段中:

#pragma    data_seg ("shared")
int      iTotal = 0 ; 

WCHAR    szStrings [MAX_STRINGS][MAX_LENGTH + 1] = { '\0' } ;
#pragma       da
ta_seg ()       

第一個#pragma敘述創建數據段,這裏命名爲shared。您能夠將這段命名爲任何一個您喜歡的名字。在這裏的#pragma敘述以後的全部初始化了的變量都放在shared數據段中。第二個#pragma敘述標示段的結束。對變量進行專門的初始化是很重要的,不然編譯器將把它們放在普通的未初始化數據段中而不是放在shared中。

連結器必須知道有一個「shared」共享數據段。在「Project Settings」對話框選擇「Link」頁面卷標。選中「STRLIB」時在「Project Options」字段(在Release和Debug設定中都可),包含下面的連結敘述:

/SECTION:shared,RWS

字母RWS表示段具備讀、寫和共享屬性。或者,您也能夠直接用DLL原始碼指定連結選項,就像咱們在STRLIB.C那樣:

#pragma comment(linker,"/SECTION:shared,RWS")
共享的內存段容許iTotal變量和szStrings字符串數組在STRLIB的全部例程之間共享。由於MAX_STRINGS等於256,而MAX_LENGTH等於63,因此,共享內存段的長度爲32,772字節-iTotal變量須要4字節,256個指針中的每個都須要128字節。

在Win16環境中,DLL的全局數據對每一個載入它的進程來講都是相同的;而在Win32環境中,狀況卻發生了變化,DLL函數中的代碼所建立的任何對象(包括變量)都歸調用它的線程或進程全部。當進程在載入DLL時操做系統自動把DLL地址映射到該進程的私有空間,也就是進程的虛擬地址空間,並且也複製該DLL的全局數據的一份拷貝到該進程空間。也就是說每一個進程所擁有的相同的DLL的全局數據,它們的名稱相同,但其值卻並不必定是相同的,並且是互不干涉的。所以,在Win32環境下要想在多個進程中共享數據,就必須進行必要的設置。在訪問同一個Dll的各進程之間共
享存儲器是經過存儲器映射文件技術實現的。也能夠把這些須要共享的數據分離出來,放置在一個獨立的數據段裏,並把該段的屬性設置爲共享。必須給這些變量賦初值,不然編譯器會把沒有賦初始值的變量放在一個叫未被初始化的數據段中。
#pragma da
ta_seg預處理指令用於設置共享數據段。例如:
#pragma da
ta_seg("SharedDataName")
HHOOK hHook=NULL;
#pragma da
ta_seg()

 在#pragma data_seg("SharedDataName")和#pragma data_seg()之間的全部變量將被訪問該Dll的全部進程看到和共享。再加上一條指令

#pragma comment(linker,"/section:.SharedDataName,rws"),

那麼這個數據節中的數據能夠在全部DLL的實例之間共享。全部對這些數據的操做都針對同一個實例的,而不是在每一個進程的地址空間中都有一份。

   1.#pragma data_seg()通常用於DLL中。也就是說,在DLL中定義一個共享的,有名字的數據段。最關鍵的是:這個數據段中的全局變量能夠被多個進程共享。不然多個進程之間沒法共享DLL中的全局變量。

   2.共享數據必須初始化,不然微軟編譯器會把沒有初始化的數據放到.BSS段中,從而致使多個進程之間的共享行爲失敗。

   3.你所謂的結果正確是一種錯覺。若是你在一個DLL中這麼寫:

#pragma data_seg("MyData")

 int g_Value; // Note that the global is not initialized.

 

#pragma data_seg()

DLL提供兩個接口函數:

int GetValue()
{
     return g_Value;
}

void SetValue(int n)
{
     g_Value = n;
}

而後啓動兩個進程A和B,A和B都調用了這個DLL,假如A調用了SetValue(5); B接着調用int m = GetValue(); 那麼m的值不必定是5,而是一個未定義的值。由於DLL中的全局數據對於每個調用它的進程而言,是私有的,不能共享的。假如你對g_Value進行了初始化,那麼g_Value就必定會被放進MyData段中。換句話說,若是A調用了SetValue(5); B接着調用int m = GetValue(); 那麼m的值就必定是5!這就實現了跨進程之間的數據通訊!


下面看一個實際應用,用共享數據來統計應用程序啓動的次數,並做相應的處理。

 

在應用程序的入口處:
//控制應用程序只能啓動一次
#pragma da
ta_seg("flag_data")
   int count=0;
#pragma da
ta_seg()
#pragma comment(linker,"/SECTION:flag_da
ta,RWS")

程序中:
   if(count>1)
     {
      MessageBox("已經啓動了一個應用程序","Warning",MB_OK);
      return FLASE;
}
   count++;

 


Visual C++ 6.0編譯指示收藏
新一篇: C++ 中的cast(顯式類型轉換) | 舊一篇: 看一我的是否快樂,不要看笑容
Document Source:

Pragma Directives, Preprocessor Reference, Visual C++ Programmer Guide.

 

每種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
 da
ta_seg
 inline_recursion
 pointers_to_members*
 
check_stack
 function
 intrinsic
 setlocale
 
co
de_seg
 hdrstop
 message
 vtordisp*
 
const_seg
 include_alias
 on
ce
 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 da
ta_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 co
de_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 da
ta_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 on
ce

指定在建立過程當中該編譯指示所在的文件僅僅被編譯程序包含(打開)一次。該編譯指示的一種常見用法以下:

//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

*/

#pragma pack( push, enter_include1 )

/* Your include-file code ... */

#pragma pack( pop, enter_include1 )

/* End of include1.h */

在前面的例子中,進入頭文件時將當前緊縮值和標示符enter_include1關聯並推入,被記住。在頭文件尾部的pack編譯選項移去全部在頭文件中可能遇到的緊縮值並移去和enter_include1關聯的緊縮值。這樣頭文件保證了在使用頭文件以前和其後的緊縮值是同樣的。

新功能也容許你在你的代碼內用pack編譯指示爲不一樣的代碼,例如頭文件設定不一樣的緊縮對齊。

#pragma pack( push, before_include1 )

#include "include1.h"

#pragma pack( pop, before_include1 )

在上一個例子中,你的代碼受到保護,防止了在include.h中的任何緊縮值的改變。

21  pointers_to_members
C++特有

#pragma pointers_to_members(pointer-declaration, [most-general-representation] )

指定是否可以在相關類定義以前說明一個指向類成員的指針,而且用於控制指針的大小和解釋指針的代碼。你可以在你的源代碼中使用pointers_to_members編譯知識來代替/vmx編譯程序選項。

pointer-declaration參數指出是否在相關函數定義以前或其後你已經說明了一個指向成員的指針。pointer-declaration參數是下面兩個符號之一:

參數
 說明
 
full_generality
 生成安全的,可是有時不能優化的代碼。若是有一些指向成員的指針在相關類定義以前說明,你要用full_generality。這個參數老是使用由most-general-representation指定的指針表示方式。
 
best_case
 對於全部指向成員的指針用最佳的表示方式生成安全的,優化的代碼。須要在說明一個指向類成員指針以前定義類。默認是best_case。
 

most-general-representaion參數指出在一個翻譯單元中編譯程序可以安全引用任何指向類成員指針的最小指針表示方式。這個參數能夠是下列之一:

參數
 說明
 
single_inheritance
 最普通的表示方式是單繼承,指向成員函數。若是用於指向具備多重或者虛擬繼承方式類成員的指針,將產生一個錯誤。
 
multi_inheritance
 最普通的表示方式是多重繼承,指向成員函數。若是用於指向具備虛擬繼承方式類成員的指針,將產生一個錯誤。
 
virtual_inheritance
 最普通的表示方式是虛擬繼承,指向成員函數。不會產生錯誤。當使用#pragma pointers_to_members (full_generality)時這是默認的參數。
 

22  setlocale
#pragma setlocale( "locale-string" )

定義用於翻譯寬字符常數和字符串文字量時用的地區(國家和語言)。因爲用於從多字節字符轉換到寬字符的算法根據地區或者因爲在運行可執行程序不一樣的地方進行編譯而不一樣,這個編譯指示提供一種在編譯時指定目標地區的方式。這保證寬字符字符串將以正確的格式保存。默認的locale-string是「C」。「C」地區將字符串中的每一個字符做爲wchar_t(即unsigned int)映射其值。

23  vtordisp
C++特有

#pragma vtordisp({on | off} )

容許隱藏的附加vtordisp構造函數/析構函數替換成員。vtordisp編譯指示僅可以用於具備虛擬基類的代碼。若是派生類從一個虛擬基類重載了一個虛擬函數,而且若是派生類的構造函數或析構函數用指向虛擬基類的指針調用了這個函數,編譯程序將根據虛擬基類在類中引入一個附加的隱藏「vtordisp」域。

vtodisp編譯選項影響它後面的類佈局。/vd0和/vd1選項爲整個模塊指定了相同的行爲。指定off將禁止隱藏的vtordisp成員,指定on(默認)將在它們須要的時候容許vtordisp。僅在不可能出現類的構造函數和析構函數經過this指針調用其指向對象中的虛擬函數時才關閉vtordisp。

#pragma vtordisp( off )

class GetReal : virtual public { ... };

#pragma vtordisp( on )

24  warning
#pragma warning( warning-specifier : warning-number-list [,warning-specifier : warning-number-list...] )

#pragma warning( push[ , n ] )

#pragma warning( pop )

容許有選擇地修改編譯程序警告信息的行爲。

warning-specifier可以是下列值之一:

warning-specifier
 含義
 
on
ce
 只顯示指定信息一次。
 
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 ] )

#pragma warning( pop )

這裏n表示警告等級(1到4)。

warning(push)編譯指示保存全部警告的當前警告狀態。warning(push,n)保存全部警告的當前狀態並將全局警告等級設置爲n。

warning(pop)彈出最後一次推入堆棧中的警告狀態。任何在push和pop之間改變的警告狀態將被取消。考慮下面的例子:

#pragma warning( push )

#pragma warning( disable : 4705 )

#pragma warning( disable : 4706 )

#pragma warning( disable : 4707 )

// Some code

#pragma warning( pop )

在這些代碼的結束,pop恢復了全部警告的狀態(包括4705,4706和4707)到代碼開始時候的樣子。

當你編寫頭文件時,你能用push和pop來保證任何用戶修改的警告狀態不會影響正常編譯你的頭文件。在頭文件開始的地方使用push,在結束地方使用pop。例如,假定你有一個不能順利在4級警告下編譯的頭文件,下面的代碼改變警告等級到3,而後在頭文件的結束時恢復到原來的警告等級。

#pragma warning( push, 3 )

// Declarations/ definitions

#pragma warning( pop )

 三 編譯選項的控制:

編譯選項對於一些工程很是有效,能夠控制多語言版本,多種編譯版本,多種編譯方式等。

選擇菜單 Build->Configurations,增長一個工程配置,在Configuration中輸入 Debug English 在 Copy Setting from 中選擇 Debug 就能夠(見下圖),使用相同的方法,再增長一個 Debug Chinese 配置,並把原來的 Debug 刪除。

選擇菜單 Project->Settings,在左邊的 Setting For 中選擇 Debug Chinese 在 Generatl 屬性頁的 Intermediate files 中輸入 Debug Chinese,在 Output files 中輸入 Chinese。在 Resource 屬性頁的 Resource file name 中輸入 Debug Chinese/Example_Ch.res,(見下圖)其它缺省就行

 

四 注意一些問題

#pragma once 與 #ifndef 解析  爲了不同一個文件被include屢次(即防止編譯屢次),C/C++中有兩種方式,一種是#ifndef方式,一種是#pragma once方式。在可以支持這兩種方式的編譯器上,兩者並無太大的區別,可是二者仍然仍是有一些細微的區別。
    方式一:

    #ifndef __SOMEFILE_H__
    #define __SOMEFILE_H__
    ... ... // 聲明、定義語句
    #endif
 

    方式二:


    #pragma once
    ... ... // 聲明、定義語句
 
    #ifndef的方式受C/C++語言標準支持。它不光能夠保證同一個文件不會被包含屢次,也能保證內容徹底相同的兩個文件(或者代碼片斷)不會被不當心同時包含。
    固然,缺點就是若是不一樣頭文件中的宏名不當心「撞車」,可能就會致使你看到頭文件明明存在,編譯器卻硬說找不到聲明的情況——這種狀況有時很是讓人抓狂。
    因爲編譯器每次都須要打開頭文件才能斷定是否有重複定義,所以在編譯大型項目時,ifndef會使得編譯時間相對較長,所以一些編譯器逐漸開始支持#pragma once的方式。

    #pragma once通常由編譯器提供保證:同一個文件不會被包含屢次。注意這裏所說的「同一個文件」是指物理上的一個文件,而不是指內容相同的兩個文件。你沒法對一個頭文件中的一段代碼做pragma once聲明,而只能針對文件。
    其好處是,你沒必要再費勁想個宏名了,固然也就不會出現宏名碰撞引起的奇怪問題。大型項目的編譯速度也所以提升了一些。
    對應的缺點就是若是某個頭文件有多份拷貝,本方法不能保證他們不被重複包含。固然,相比宏名碰撞引起的「找不到聲明」的問題,這種重複包含很容易被發現並修正。

    #pragma once方式產生於#ifndef以後,所以不少人可能甚至沒有據說過。目前看來#ifndef更受到推崇。由於#ifndef受C/C++語言標準的支持,不受編譯器的任何限制;而#pragma once方式卻不受一些較老版本的編譯器支持,一些支持了的編譯器又打算去掉它,因此它的兼容性可能不夠好。通常而言,當程序員聽到這樣的話,都會選擇#ifndef方式,爲了努力使得本身的代碼「存活」時間更久,一般寧願下降一些編譯性能,這是程序員的個性,固然這是題外話啦。

    還看到一種用法是把二者放在一塊兒的:

    #pragma once
    #ifndef __SOMEFILE_H__
    #define __SOMEFILE_H__
    ... ... // 聲明、定義語句
    #endif
 
    看起來彷佛是想兼有二者的優勢。不過只要使用了#ifndef就會有宏名衝突的危險,也沒法避免不支持#pragma once的編譯器報錯,因此混用兩種方法彷佛不能帶來更多的好處,卻是會讓一些不熟悉的人感到困惑。

    選擇哪一種方式,應該在瞭解兩種方式的狀況下,視具體狀況而定。只要有一個合理的約定來避開缺點,我認爲哪一種方式都是能夠接受的。而這個已經不是標準或者編譯器的責任了,應當由程序員本身或者小範圍內的開發規範來搞定。

    btw:我看到GNU的一些討論彷佛是打算在GCC 3.4(及其之後?)的版本取消對#pragma once的支持。不過事實上,我手上的GCC 3.4.2和GCC 4.1.1仍然支持#pragma once,甚至沒有deprecation warning,卻是GCC2.95會對#pragma once提出warning。
    VC6及其之後版本亦提供對#pragma once方式的支持,這一特性應該基本穩定下來了。

原文http://blog.csdn.net/omgle/article/details/6770583

相關文章
相關標籤/搜索