編譯指示指令

第2章 編譯指示指令
C和C++的每個實現對它的主機或操作系統都支持一些獨有的特徵。例如,某些程序須對存放數據的存儲器區域進行精確的控制,或必須控制特定函數接受參量的方式。#pragma指令對每個編譯器給出了一個方法,在保持與C和C++語言完全兼容的情況下,給出主機或操作系統專有的特徵。依據定義,編譯指示是機器或操作系統專有的,且對於每個編譯器都是不同的。

語法

#pragma 語言符號字符串

語言符號字符串是給出特有編譯器指令和參量的字符序列。數字符號(#)必須是包含編譯指示行中的第一個非空白字符。空白字符可分開數字符號(#)和單詞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++編譯器支持

 

C++編譯器專有編譯指示

以下是C++編譯器專有的編譯指示指令:

* init_segl

pointers_to_members

* vtordisp

init_seg

C++特殊處

#pragma init-seg({complier/lib/user/ "section-name" [,"func-name"]})該指令指定一個影響啓動代碼執行順序的關鍵字或代碼段。由於全局靜態對象的初始化可能涉及執行代碼,因此必須指定創建對象時定義的一個關鍵字。在動態連接庫(DLL)或需初始化的庫中使用init_seg編譯指示尤其重要。

init_seg編譯指示的選項如下:

complier

該選項保留給Microsoft C運行庫初始化。這個組中的對象最先被創建。lib 用於第三方類庫供應商的初始化。該組中的對象在complier標誌之後,其他標記之前創建。

user

用於任何用戶。此組對象最後創建。

section_name

允許初始化段的顯示規格。在一個用戶指定section-name(段名稱)中的對象不能被隱含地創建,但它們的地址可放在以section_name命名的段中。

func_name

指定在程序退出時在exit()地方調用的函數。指定的函數必須與exit函數具有相同的特徵:int funcname(void(__cdecl*)(void));

如果你需要延遲初始化過程(例如,在一個DLL中),你可以選擇顯式地指定該段名稱。然後必須爲每個靜態對象調用構造函數。

C++特殊處結束

pointers_to_members

C++特殊處

#progma pointers_to_members(指針說明,[最一般表示])

該指令指定一個類成員的指針能否在其相關定義之前被說明,且用於控制該指針尺寸和解釋該指針需要的代碼。你可以把一個pointers_to_members編譯指示放入你的源文件中替換/vmx編譯器選項。

指針說明參量指定你在一個關聯函數定義之前還是之後說明了一個成員的指針。指針說明參量是以下兩個符號之一:

 

參量 說明
full_generality 生成安全、但常常並非最優的代碼。如果在關聯類定義之前說明任何成員的指針,可使用full_generality。該參量通常使用最一般表示參量指定的指針表示形式。等同於/vmg選項
best_case 爲所有成員指針使用最佳情況(best__case)表示生成安全的最優代碼。使用該參量是需在定義一個類的成員指針說明之前定義此類。其缺省值爲best_case

best_case 爲所有成員指針使用最佳情況(best__case)表示生成安全的最優代碼。使用該參量是需在定義一個類的成員指針說明之前定義此類。其缺省值爲best_case

最一般表示參量說明了在轉換單元中,編譯器能夠安全地引用任何指向類成員的指針的最小指針表示。該參量取如下值之一:

參量 說明
single_inheritance 最一般表示是單繼承的,即一個成員函數的指針。對於其中說明了一個指向成員指針的一個類定義,若其繼承模式說明爲多重的或虛擬的,將導致錯誤
multiple_inheritance 最一般表示是多重繼承的,即一個成員函數的指針。對於其中說明了一個指向成員指針的一個類定義,若其繼承模式是虛擬的,將導致錯誤
vitual_inheritance 最一般表示是虛擬繼承,即一個成員函數的指針。該函數不會導致錯誤。當使用#pragmapointers_to_members(full_generality) 時這是個缺省參量

C++特殊處結束

vtordisp

C++特殊處

#pragma vtordisp({on|off})

該指令允許增加隱含的vtordisp構造函數/析構函數替換成員。vtordisp編譯指示只使用虛基類的代碼。若一個派生類重迭一個從虛擬基類繼承的虛擬函數,且如果派生類的一個構造函數或析構函數調用那個使用該虛擬基類指針的函數,則編譯器可能將增加的隱含“vtordisp”域到有虛擬基的類中。

vtordisp編譯指示會影響其後類的分佈。/Vd0或/Vd1選項指定了對於完全模式的相同動作。指定off將抑制隱含的vtordisp成員。指定缺省值on,將在需要的位置打開它們。Vtordisp指令僅在類的構造/析構函數在用this指針指向的對象處不可能調用虛擬函數時關閉。

#pragma vtordisp(off)

class GetReal:virtual public{...};

#pragma vtordisp(on)

C++特殊處結束

C和C++編譯器編譯指示

以下是爲C和C++編譯器定義的編譯指示:

alloc_text component init_seg* optimize

auto_inline const_seg inline_depth pack

bss_seg data_seg inline_recursi onpointers_to_members*

check_stack function intrinsic setlocale

code_seg hdrstop message vtordisp*

comment include_alias once warning

* 僅被C++編譯器支持

alloc_text#pragma alloc_text(“文本段”,函數1,...)

該指令用於命名指定的函數定義將要駐留的代碼段。該編譯指示對已命名的函數必須出現在一個函數說明符和該函數定義之間。

alloct_text編譯指示並不處理C++成員函數或重載函數。它僅用於以C連接方式說明的函數,這指的是用extern“C”連接規格說明的函數。如果你試圖將此編譯指示用於非C++連接的函數,將產生一個編譯錯誤。

由於不支持使用__based的函數地址,指定段位址需要使用alloc_text編譯指示,以文本段指定的名稱應包括在雙引號間。

alloc_text編譯指示必須出現在指定的函數說明之後,這些函數的定義之前。一個alloc_text編譯指示中的函數引用必須在此編譯指示的同一模塊中定義。如果未這樣做,且一個未定義的函數隨後被編譯到一個不同的文本段,則這個錯誤可能找得到,也可能找不到。雖然該程序一般會正常運行,但該函數不會分配到預期的段中。

alloc_text的其他限制如下:

* 它不能用在一個函數的內部。

* 它必須在已說明的函數之後和已定義的函數之前使用。

auto_inline

#pragma auto_inline([{on|off}])

排除自動內聯擴展的候選者中指定爲off的區域中定義的函數。爲了使用auto_inline編譯指示,把它放在一個函數定義之前或立即之後(不在該函數定義之內)。在看到該編譯指示之後的第一個函數定義處,該編譯指示發生作用。編譯指示auto_inline不能應用於顯式內聯函數。

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用於與Visual C++之前的版本兼容,現在已被忽略。

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 - 是或否 關閉其後函數的棧檢查
code_seg

#pragma code_seg(["section-name"[,"section-class"]])

該指令用於指定一個分配函數的代碼段。code_seg編譯指示指定了函數的缺省段。

你可以有選擇性地指定類和段名。使用沒有section-name字符串的#pragmacode_seg可在編譯開始時將其復位。

const_seg

#pragma const_seg(["section-name"[,"section-class"]])

該指令用於指定對於常量數據的缺省段。data_seg編譯指示對所有數據具有相同作用。你可以用此指令將你的所有常量數據放入一個只讀段中。

#pragma const_seg("MY_DATA")

導致該指令將#pragma語句後的常量數據放入一個名稱爲MY_DATA的段裏。

使用const_seg編譯指示分配的數據不會保留有關它的位置的任何信息。

第二個參數section-class用於與Visual C++ 2.0版之前的版本兼容,現在已可忽略。

comment

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

該指令將一個註釋記錄放入一個對象文件或可執行文件中。comment-type是下面五種說明的預定義標識符之一,它們指出了註釋記錄的類型。任選的commentstring是給一些註釋類型提供額外信息的字符串文字。由於commentstring是一個字符串文字,因此它必須遵循對於字符串文字的諸如轉義字符、嵌入或引號標記(")以及合併的所有規則。

complier

該選項將編譯器的名稱和版本號放入對象文件中。這個註釋記錄被鏈接器忽略,如果你爲這個記錄類型給出一個commentstring參量,該編譯器將產生一個警告信息。

exestr

該選項將commentstring放入對象文件中。在連接時,該字符串被置入可執行文件中。

該字符串並不與可執行文件同時加載到存儲器,但它可用在文件中尋找可打印字符串的程序找到。這個註釋記錄類型的一個用途是把版本號或類似信息嵌入到一個可執行文件中。

lib

該選項將一個庫搜索記錄放入對象文件。該註釋類型必須帶有一個commentstring參數。這個參數包含你想要的鏈接器搜索的庫的名稱(有可能包含路徑)。由於在對象文件中該庫名稱在缺省的庫搜索記錄之前,所以鏈接器搜索該庫就象你在命令行中命名了它一樣。你可以把多個庫搜索記錄放在同一個源文件中,每個記錄在對象文件中都以其在源文件中出現的同樣順序出現。

linker

該選項將一個鏈接器選項放入對象文件中。可以用該註釋類型指定一個鏈接器選項,用於取代在Project Setting對話框中Link選項卡上放入該選項。例如,你可以指定/include選項來強行包括一個符號:

#pragma comment(linker,"/include:__symbol")

user

該選項將一個一般的註釋放入對象文件中。commentstring參量包含了該註釋的文本。這個註釋記錄被鏈接器忽略。

以下編譯指示導致鏈接器在連接時搜索EMAPI.LIB庫。該連接器首先在當前工作目錄中搜索,隨後在LIB環境變量說明的路徑中搜索。

#pragma comment(lib,"emapi")

以下編譯指示導致編譯器把編譯器的名稱和版本號放入對象文件:

#pragma comment(complier)

注意:對於一個帶commentstring參量的註釋,你可以在任何要使用一個字符串文字的地方使用宏,讓這個宏擴展爲一個字符串文字。你也可以把任何一個字符串文字的任何組合與擴展爲字符串文字的宏合併起來,例如:下面的語句是可以接受的:

#pragma comment(user,"Compiled on" __DATA_ _ "at" _ _TIME_ _)

component#pragma

component(browser,{on|off}[,references[,name]])#pragma component(minrebuild,on|off)

該指令用於控制源文件內的瀏覽信息或依賴信息的集合。

browser

你可以打開或關閉集合,並可以在收集信息時指定忽略的特定名稱。

用on或off選項控制前面編譯指示的瀏覽信息的集合。例如:

#pragma component(browser,off)

該指令讓編譯器停止收集瀏覽信息。

注意:用此指令打開瀏覽信息的集合,瀏覽信息必須先用Project Settings對話框或命令行打開。

references選項可帶也可不帶name參量。不帶name參量的references選項用於打開或關閉引用的集合(但此時繼續收集其它瀏覽信息)。例如:

#pragma component(browser,off,references)

該指令使編譯器停止收集引用信息。

帶name和off參量的references選項,用於防止瀏覽信息窗口中出現對name的引用。使用這種語法可忽略你不感興趣的名稱和類型,並且可縮短瀏覽信息的尺寸。例如:

#pragma component(browser,off,references,DWORD)

忽略該點之前對於DWORD的引用。但你可用on選項把對於DWORD引用的集合重新打開。

#pragma component(browser,on,references,DWORD)

這是恢復對name引用集合唯一的方式;用此方式你可以顯式地打開任何你已經關閉的name。

爲了防止預處理器把name展開(如把NULL擴展爲0),將它加上引號:

#pragma component(browser,off,references,"NULL")

Minimal Rebuild

Visual C++的minimal rebuild(最小重建)特性需要編譯器創建和存儲依賴信息的C++類,這將佔用磁盤空間。爲了節省磁盤空間,你可以在任何你不需收集依賴信息的時候僅用#pragma component(minirebuild,off),例如,在不變的頭文件中。在不變的類後插入#pragma component(minrebuild,on)可重新打開依賴信息。

有關更多的信息參見Enable Minimal Rebuild(/Gm)編譯器選項。

data_seg

#pragma data_seg(["section-name"[,"section-class"]])

該指令指定數據的缺省段。例如:

#pragma data_seg("MY_DATA")

將#pragma語句後分配的數據放在以名稱爲MY_DATA的段裏。

使用data_seg編譯指示分配的數據不會保留關於它的位置的任何信息。

第二個參量section-class用於與Visual C++ 2.0之前的版本兼容,現在已可忽略。

function

#pragma function(function1[,function2,...])

該指令指定對在生成的編譯器編譯指示參量表中指定調用的函數。如果你使用intrinsic編譯指示(或/Oi)告訴編譯器生成內在函數(被生成爲內聯代碼,而非函數調用的內在函數),就能用function編譯指示來顯式地強制調用一個函數。當一個函數編譯指示出現時,它在第一個包含一個指定的內在函數的函數定義處發生作用,這個作用持續到源文件的結尾或直到一個說明這種相同的內在函數的編譯指示出現爲止。在全局層時,該function編譯指示只能用在一個函數外。對於具有內部形式的函數表,參見#pragma intrinsic。

hdrstop

#pragma hdrstop[("filename")]

該指令用於控制預編譯頭文件的工作方式。filename是預編譯頭文件使用或創建的名稱(根據指定選項/Yu或/Yc決定)。如果filename不包含路徑說明,預編譯頭文件將被假定在與源文件相同的目錄中。當指定/YX自動預編譯頭文件選項時,所有filename都被忽略。

當採用/YX或/Yc編譯時,一個C或C++文件包含一個hdrstop編譯指示,該編譯器將把編譯狀態存入到編譯指示的位置。該編譯指示之後任何代碼的編譯狀態都不存儲。

hdrstop編譯指示不可能出現在一個頭文件中。它必須出現在源文件中。這指的是,它不能出現在任何數據、函數說明或函數定義中。

注意:除非/YX選項或無文件名的/Yu或/Yc選項被指定,否則hdrstop編譯指示將被忽略。

該指令使用filename命名編譯狀態存儲的預編譯頭文件。hdrstop和filename之間的一個空白是任選的。在hdrstop編譯指示中說明的文件名稱是一個字符串,而且必須服從C或C++字符串的約束。尤其重要的是必須將其置於括號中

如下例所示:

#pragma hdrstop("c:/projects/include/myinc.pch")

預編譯頭文件的名稱由下列規則決定,順序如下:

1. /Fp編譯器選項的參量。

2. #pragma hdrstop的filename參量。

3. 以.PCH爲擴展名的源文件的基名稱。

include_alias

#pragma include_alias("long_filename","short_filename")

#pragma include_alias(,)

該指令指定short_filename作爲long_filename的別名。某些文件系統允許比8.3 FAT文件系統限定更長的文件名。編譯器不能夠簡單地把更長的頭文件名截短爲8.3格式,因爲這種更長的頭文件名的開始八個字符可能不是唯一的。只要編譯器遇到long_filename字符串,就用short_filename替換,並且代替查找short_filename頭文件。這個編譯指示必須出現在相應的#include指令之前,

例如:/

/這兩個文件的開頭八個字符不是唯一的

#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

相應的編譯器選項應該是:

/YcAppleSystemHeaderStop.h

你可以用include_alias編譯指示把任何頭文件名映射爲另一個。例如:

#pragma include_alias("api.h", "c:/version1.0/api.h")

#pragma include_alias(, )

#include "api.h"

#include

不要把雙引號內的文件名和尖括號內的文件名相混淆,例如,對於上面給出的兩個#pragma include_alias指令,編譯器在下面的#include指令中不執行任何替換:

#include

Include "stdio.h"

此外,下面的指令將導致錯誤:

#pragma include_alias(,"header.h") //錯誤

注意在錯誤信息中給出的文件名,或作爲預先定義的__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。

inline_depth

#pragma inline_depth([0...255])

該指令通過控制一系列函數調用能被擴展的次數(從0到255次),來控制內聯擴展可發生的次數。這個編譯指示控制標記爲inline和_ _inline的函數的聯編或在/Ob2選項下已經自動聯編的函數。

inline_depth編譯指示控制一序列函數調用能被擴展的次數,例如,若聯編深度爲4,且若A調用B,B調用C,三個調用都將內聯擴展。但如果最近的內聯擴展爲2,只有A和B被擴展,C保留爲一個函數調用。

爲使用這個編譯指示,你必須設置/Ob編譯器選項爲1或2。使用這個編譯指示的深度設置在該編譯指示指令後的第一個函數處生效。如果你沒有在圓括號中指定一個值,inline_depth將設置聯編深度爲缺省值8。

聯編深度在擴展時只減不增。若聯編深度爲6,且在擴展時,預處理器遇到一個聯編深度值爲8的inline_depth編譯指示,該深度仍保持爲6。

聯編深度0禁止聯編擴展;聯編深度255對聯編擴展無限制,若使用一個未指定其值的編譯指示,則將使用其缺省值。

inline_recursion

#pragma inline_recursion([{on|off}])

該指令控制直接或相互遞歸函數調用的聯編擴展。該指令用於控制標記爲inline和_ _inline的函數,或編譯器在Ob2選項下自動擴展的函數。這個編譯指示的用法需要一個設置爲1或2的/Ob編譯器選項。inline_recursion的缺省狀態是off。這個編譯指示只是在其出現之後的第一個函數處起作用,並且不會影響該函數的定義。

inline_recursion編譯指示控制遞歸函數如何被擴展。如果inline_recursion關閉,且若一個聯編函數調用其自身(直接或間接),該函數只被擴展一次。若inline_recursion爲打開狀態,則該函數將被擴展多次直到其達到inline_depth的值,或達到其容量值的限制。

intrinsic#pragma

intrinsic(function1[,function2,...])

該指令指定對於在編譯指示參量表中說明的函數的調用是內在的。編譯器生成象聯編代碼的內在函數,而並不像函數調用那樣。具有內在格式的庫函數如下表。當遇到一個intrinsic編譯指示時,它在一個包含指定的內在函數的第一個函數定義處發生作用,其作用延續到源文件的結尾,或直到一個說明相同的內在函數的function編譯指示出現爲止。

intrinsic編譯指示只能用在一個函數定義之外(全局級)。

以下函數具有內在格式:

_disable _outp fabs strcmp

_enable _outpw labs strcpy

_inp _rotl memcmp strlen

_inpw _rotr memcpy

_lrotl _strset memset

_lrotr abs strcat

使用內在函數的程序更快,因爲它們沒有函數調用的額外開銷,但由於產生的額外代碼,它們會更大一些。

注意:_alloca和setjmp函數總是聯編生成的,這種行爲不會受intrinsic編譯指示的影響。

以下所列的浮點函數沒有真正的內在格式。但它們有這樣的版本:將參量直接送入浮點芯片,而不是將它們壓入程序棧中:

acos cosh pow tanh

asin fmod sinh

當你指定/Oi和/Og編譯器選項(或任何包括/Og、/Ox、/O1和/O2的選項)時,以下浮點函數有真正的內在格式:

atan exp log10 sqrt

atan2 log sin tan

cos

你可以使用/Op或/Za編譯器選項重迭真正的內在浮點選項的生成。這種情況下,該函數被生成爲庫例程,該例程直接把參量送入浮點芯片,而不是把它們壓入程序棧。

message

#pragma message(messagestring)

該指令不終止編譯,直接把一個字符串文字送到標準輸出。message編譯指示的典型用法是在編譯時顯示信息消號。以下代碼段使用message編譯指示在編譯時顯示一個消息:

#if _M_IX86==500

#pragma

message("Pentium processor build")#endifmessagestring參數可以是可擴展爲一個字符串文字的宏,並且你可以以任何組合方式用字符串文字將這些宏合併起來。例如,下列語句顯示了被編譯的文件名以及該文件最後改動的日期和時間:

#pragma message("Compiling "__FILE__ )

#pragma message("Last modified on " __TIMESTAMP_ _)

once

#pragma once

該指令指定該編譯指示駐留的文件將只在一次建立中被編譯器包括(打開)一次。該編譯指示的一種普通用法如下:

//header.h

#pragma once

//接着是你的C或C++代碼

optimize

#pragma optimize( "[optimization-list]",{on|off} )

僅用於專業和企業版本的特徵:代碼優化只被Visual C++專業版和企業版支持。更多的信息參見Microsoft Visual C++聯機編輯。

該指令指定在函數基中執行的優化。optimize編譯指示必須出現在一個函數之外,並且在編譯指示出現後定義的第一個函數處產生作用。on和off參量可以打開或關閉在Optimization-list中指定的選項。

optimization-list可以是0或在表2.2中給出參數。

表2.2 "優化"編譯指示的參數

 

參量 優化類型
a 假定無別名
g 允許全局優化
p 提高浮點相容性
s或t 指定機器碼的短或快序列
w 假定無交叉函數調用的別名
y 生成程序堆棧中的框架指針
這些是採用/O編譯器選項的相同字母,例如:

#pragma optimize("atp", on)

用空字符串("")使用optimize編譯指示是該指令的一種特殊形式,它可關閉所有的優化或恢復它們的原有(缺省的)設置。

#pragma optimize("",off)

...

#pragma optimize("", on)

pack

#pragma pack([n])

該指令指定結構和聯合成員的緊湊對齊。而一個完整的轉換單元的結構和聯合

的緊湊對齊由/Zp選項設置。緊湊對齊用pace編譯指示在數據說明層設置。該編譯指示在其出現後的第一個結構或聯合說明處生效。該編譯指示對定義無效。當你使用#pragma pack(n)時,這裏n爲1、2、4、8或16。第一個結構成員之後的每個結構成員都被存儲在更小的成員類型或n字節界限內。如果你使用無參量的#pragma pack,結構成員被緊湊爲以/Zp指定的值。該缺省/Zp緊湊值爲/Zp8。

編譯器也支持以下增強型語法:

#pragma pack([[{push|pop},][標識符,]][n])

若不同的組件使用pack編譯指示指定不同的緊湊對齊,這個語法允許你把程序組件組合爲一個單獨的轉換單元。

帶push參量的pack編譯指示的每次出現將當前的緊湊對齊存儲到一個內部編譯器堆棧中。編譯指示的參量表從左到右讀取。如果你使用push,則當前緊湊值被存儲起來;如果你給出一個n的值,該值將成爲新的緊湊值。若你指定一個標識符,即你選定一個名稱,則該標識符將和這個新的的緊湊值聯繫起來。

帶一個pop參量的pack編譯指示的每次出現都會檢索內部編譯器堆棧頂的值,並且使該值爲新的緊湊對齊值。如果你使用pop參量且內部編譯器堆棧是空的,則緊湊值爲命令行給定的值,並且將產生一個警告信息。若你使用pop且指定一個n的值,該值將成爲新的緊湊值。

若你使用pop且指定一個標識符,所有存儲在堆棧中的值將從棧中刪除,直到找到一個匹配的標識符,這個與標識符相關的緊湊值也從棧中移出,並且這個僅在標識符入棧之前存在的緊湊值成爲新的緊湊值。如果未找到匹配的標識符,將使用命令行設置的緊湊值,並且將產生一個一級警告。缺省緊湊對齊爲8。

pack編譯指示的新的增強功能讓你編寫頭文件,確保在遇到該頭文件的前後的緊湊值是一樣的。

/* File name: include1.h*/

#pragma pack(push,enter_include1)

/* 你的包括文件代碼... */

#pragma pack(pop, enter_include1)

/* include1.h結束 */

在上面的例子中,當前緊湊值與標識符enter_include1聯繫起來,並被壓入頭文件的項中。頭文件末尾的pack編譯指示刪除所有可能出現在頭文件中的干預緊湊值,並且刪除與enter_include1相關的緊湊值。因此確保該頭文件的前後的緊湊值是相同的。

這種新功能也允許你使用代碼,例如頭文件,它可以使用pack編譯指示設置不同於在你的代碼中設置的緊湊值的緊湊對齊:

#pragma pack(push,before_include1)

#include "include1.h"

#pragma pack( pop,before_include1)

在上面的例子中,對於出現在include.h中的緊湊值的任何變化,你的代碼是受到保護的。

setlocale

#pragma setlocale("locale_string")

該指令在翻譯寬字符常量和字符串文字時定義其場所(國家和語言)。由於用於轉換多字節字符爲寬位字符的算法可能由於場所或編譯而不同,該執行文件在不同的場所運行也可能不同。這個編譯指示提供了在編譯時給出目標場所的方法。這保證了寬字符串以正確的格式進行存儲。缺省的locale_ _string(場所字符串)是“C”。“C”場所將每個該串中的字符映射爲一個wchar_t(unsigned short)型的值。

warning

#pragma warning( warning-specifier:warning-number-list

[,warning-specifier:warning-number-list...])

#pragma warning(push[,n])#pragma warning(pop)

該指令允許選擇性地改變編譯器的警告消息。

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

警告指示符 含義

once 只顯示一次指定的消息default將缺省的編譯器行爲應用於指定的消息

1,2,3,4 把給定的警告級應用於指定的警告消息

disable 不發出指定警告消息

error 作爲錯誤報告指定的警告

warning-number-list(警告編號表)可以包含任何警告編號。在相同的編譯指示指令中可指定多個選項如下:

#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

對於那些與代碼生成有關,且大於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)

// 某些代碼

#pragma warning(pop)

在這段代碼的未尾,pop恢復所有警告狀態(包括4705、4706和4707)爲它在代碼起始處的警告狀態。

當你編寫頭文件時,可以用push和pop以確保對於用戶造成的警告狀態的變化,不會影響頭部的正確編譯。通常在頭部的起始處使用push,在末尾處使用pop。例如,有一個在警告級4未徹底編譯的頭部。以下代碼將警告級改爲3,然後在頭部的未尾恢復原來的警告級:

#pragma warning(push,3)

//說明/定義

#pragma warning(pop)

發佈了64 篇原創文章 · 獲贊 102 · 訪問量 138萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章