接上一篇#pragma編譯指令大全(上)
inline_depth
語(yǔ)法
#pragma inline_depth( [n] )
作用
指定函數(shù)的內(nèi)斂深度,超過深度n的內(nèi)斂擴(kuò)展均轉(zhuǎn)為函數(shù)調(diào)用。
備注
- inline_depth的控制范圍是用inline,__inline標(biāo)記或在/Ob2編譯選項(xiàng)下能夠自動(dòng)內(nèi)斂的函數(shù)。
- n的取值范圍是[0,255], 0代表禁用內(nèi)斂,255表示不限制內(nèi)斂深度。未指定n值情況下默認(rèn)為254。
- inline_depth可以控制一些列函數(shù)調(diào)用的內(nèi)斂深度。舉例,假設(shè)內(nèi)斂深度是4,如果A調(diào)用B然后調(diào)用C,所有的3次調(diào)用都將做內(nèi)斂擴(kuò)展。然而,如果設(shè)置的最近一次內(nèi)斂深度是2,則只有A和B被擴(kuò)展,而C仍然作為函數(shù)調(diào)用。
- 要使用該指令,必須設(shè)置編譯選項(xiàng)為/Ob1或/Ob2,并且在該指令設(shè)定內(nèi)斂深度后的第一個(gè)函數(shù)生效。
- 嵌套的內(nèi)斂深度設(shè)置只能遞減,不能遞增。如果內(nèi)斂深度為6,同時(shí)后續(xù)通過inline_depth編譯指令設(shè)置為8,則內(nèi)斂深度仍保持為6。
- inline_depth對(duì)使用__forceinline標(biāo)記的函數(shù)無效。
遞歸函數(shù)的內(nèi)斂深度為16。
inline_recursion
語(yǔ)法
#pragma inline_recursion( [{on | off}] )
作用
控制直接或間接遞歸調(diào)用函數(shù)的內(nèi)斂展開。
備注
- inline_recursion的控制范圍是用inline,__inline標(biāo)記或在/Ob2編譯選項(xiàng)下能夠自動(dòng)內(nèi)斂的函數(shù)。
- 要使用該指令,必須設(shè)置編譯選項(xiàng)為/Ob1或/Ob2,并且在該指令設(shè)定開關(guān)后的第一個(gè)函數(shù)生效。
- 默認(rèn)情況下開關(guān)為off。
- 如果開關(guān)為off,且內(nèi)斂函數(shù)調(diào)用自身,則該函數(shù)只展開一次。
- 如果開關(guān)為on,則該函數(shù)將展開多次,直至達(dá)到使用inline_depth設(shè)定的內(nèi)斂深度。
intrinsic
語(yǔ)法
#pragma intrinsic( function1 [, function2, ...] )
作用
指定參數(shù)列表中的函數(shù)為內(nèi)建函數(shù)。
備注
- intrinsic告訴編譯器函數(shù)行為明確,如果性能更好的情況下可以直接調(diào)用函數(shù)而無需采用內(nèi)斂展開。
- 在intrinsic指令出現(xiàn)之后的第一個(gè)包含內(nèi)建函數(shù)的函數(shù)定義開始生效。作用效果持續(xù)到源文件末尾或者遇到funtion編譯指令指定相同的函數(shù)。
- intrinsic只能在函數(shù)定義外使用-在全局層次。
- 下面是具有內(nèi)建形式的庫(kù)函數(shù)。
row1 | row2 | row3 |
---|---|---|
_disable | _outp | fabs |
_enable | _outpw | labs |
_inp | _rotl | memcmp |
_inpw | _rotr | memcpy |
_lrotl | _strset | memset |
_lrotr | abs | strcat |
strcmp | strcpy | strlen |
*5. 使用intrinsic函數(shù)的程序之所以運(yùn)行速度更快,是因?yàn)樗鼪]有函數(shù)調(diào)用的開銷,但是由于插入了額外的代碼,所以程序會(huì)更大。
*6. 下列的浮點(diǎn)數(shù)函數(shù)不具有真正的intrinsic形式,它們可以直接將浮點(diǎn)參數(shù)傳到浮點(diǎn)芯片中,而不是將參數(shù)壓入程序堆棧。
row1 | row2 | row3 | row4 |
---|---|---|---|
acos | cosh | pow | tanh |
asin | fmod | sinh |
*7. 當(dāng)指定編譯選項(xiàng)/Oi、/Og和/fp:fast(或任何包含/Og的選項(xiàng):/Ox、/O1和/O2)時(shí),下面列出的浮點(diǎn)函數(shù)將具有真正的intrinsic形式。
row1 | row2 | row3 | row4 |
---|---|---|---|
atan | exp | log10 | sqrt |
atan2 | log | sin | tan |
cos |
示例代碼
// pragma_directive_intrinsic.cpp
// processor: x86
#include <dos.h> // definitions for _disable, _enable
#pragma intrinsic(_disable)
#pragma intrinsic(_enable)
void f1(void) {
_disable();
// do some work here that should not be interrupted
_enable();
}
int main() {
}
loop
語(yǔ)法
#pragma loop( hint_parallel(n) )
#pragma loop( no_vector )
#pragma loop( ivdep )
作用
控制對(duì)循環(huán)代碼的自動(dòng)并行化和自動(dòng)向量化。
備注
- hint_parallel(n): 提示編譯器對(duì)循環(huán)代碼進(jìn)行n線程并行。n為0時(shí)采用最大數(shù)量的線程。該指令只是一個(gè)提示,并不是命令,編譯器不能保證將循環(huán)并行化。
- 如果循環(huán)具有數(shù)據(jù)依賴或結(jié)構(gòu)化問題,比如循環(huán)存儲(chǔ)了循環(huán)體外的標(biāo)量,將不會(huì)并行化。
- 只有指定/Qpar編譯選項(xiàng)時(shí),hint_parallel才會(huì)生效。
- no_vector:默認(rèn)情況下,自動(dòng)向量化時(shí)打開的。
- idevp:提示編譯器忽略該循環(huán)的向量依賴。
- loop編譯指令需要放在緊挨著循環(huán)體之前,不能放在循環(huán)體內(nèi),并且對(duì)接下來的循環(huán)生效。
- 可以對(duì)同一個(gè)循環(huán)體指定多個(gè)loop選項(xiàng),但是每個(gè)選項(xiàng)都要使用單獨(dú)一條指令。
make_public
語(yǔ)法
#pragma make_public(type)
作用
指示本機(jī)類型應(yīng)具有公共程序集可訪問性。
備注
- type: 需要具有公共程序集可訪問性的類型名稱。
- 如果要引用的本機(jī)類型來自無法更改的.h文件,則 make_public 會(huì)很有用。
- 若要在帶有公共程序集可見性的類型中使用公共函數(shù)簽名中的本機(jī)類型,則本機(jī)類型還必須具有公共程序集可訪問性,否則編譯器將發(fā)出警告。
- make_public必須在全局范圍內(nèi)使用,并且僅在編譯指令指定處到源文件末尾有效。
- 可以隱式或顯式將本機(jī)類型設(shè)為私有;詳細(xì)信息請(qǐng)參閱類型可見性。
示例代碼
// make_public_pragma.h
struct Native_Struct_1 { int i; };
struct Native_Struct_2 { int i; };
// make_public_pragma.cpp
// compile with: /c /clr /W1
#pragma warning (default : 4692)
#include "make_public_pragma.h"
#pragma make_public(Native_Struct_1)
public ref struct A {
void Test(Native_Struct_1 u) {u.i = 0;} // OK
void Test(Native_Struct_2 u) {u.i = 0;} // C4692
};
注意上述代碼示例指定的編譯選項(xiàng):/c /clr /W1
managed, unmanaged
語(yǔ)法
#pragma managed
#pragma unmanaged
#pragma managed([push,] on | off)
#pragma managed(pop)
作用
啟用函數(shù)級(jí)控制以將函數(shù)編譯為托管或未托管函數(shù)。
備注
- /clr編譯器選項(xiàng)提供了用于將函數(shù)編譯為托管或非托管函數(shù)的模塊級(jí)控制。
- 非托管函數(shù)將在本機(jī)平臺(tái)編譯成機(jī)器碼,并且由CLR傳給本機(jī)平臺(tái)運(yùn)行。
- 啟用/clr編譯選項(xiàng)后,默認(rèn)情況下將函數(shù)編譯為托管函數(shù)。
- 該編譯指令需要放在函數(shù)體之前,不能放在函數(shù)體內(nèi)。
- 該編譯指令必須放在#include指令之后。
- 如果未設(shè)定/clr編譯選項(xiàng),編譯器將忽略managed和unmanaged編譯指令。
- 該編譯指令可以在模板函數(shù)實(shí)例化之后確定該函數(shù)是否為托管函數(shù)。
- 更多詳細(xì)信息請(qǐng)參閱混合程序集的初始化;
示例代碼
// pragma_directives_managed_unmanaged.cpp
// compile with: /clr
#include <stdio.h>
// func1 is managed
void func1() {
System::Console::WriteLine("In managed function.");
}
// #pragma unmanaged
// push managed state on to stack and set unmanaged state
#pragma managed(push, off)
// func2 is unmanaged
void func2() {
printf("In unmanaged function.\n");
}
// #pragma managed
#pragma managed(pop)
// main is managed
int main() {
func1();
func2();
}
In managed function.
In unmanaged function.
message
語(yǔ)法
#pragma message( messagestring )
作用
在不中斷編譯的情況下將字符串輸出到標(biāo)準(zhǔn)輸出窗口。
備注
- 該編譯指令的典型用法是輸出信息性消息。
- messagestring可以是宏,也可以是字符串和宏的拼接。
- 在該編譯指令中使用的宏應(yīng)該返回字符串類型,否則需要主動(dòng)將宏返回信息轉(zhuǎn)換成字符串類型。
示例代碼
// pragma_directives_message1.cpp
// compile with: /LD
#if _M_IX86 >= 500
#pragma message("_M_IX86 >= 500")
#endif
#pragma message("")
#pragma message( "Compiling " __FILE__ )
#pragma message( "Last modified on " __TIMESTAMP__ )
#pragma message("")
// with line number
#define STRING2(x) #x
#define STRING(x) STRING2(x)
#pragma message (__FILE__ "[" STRING(__LINE__) "]: test")
#pragma message("")
omp
語(yǔ)法
#pragma omp directive
作用
將一個(gè)或多個(gè)OpenMP指令與任何可選指令子集一起使用。
once
語(yǔ)法
#pragma once
作用
指定該文件在編譯源文件時(shí)僅被編譯器包含(打開)一次。
備注
- 該編譯指令可以減少編譯次數(shù),通常被稱為多次包含優(yōu)化(multiple-include optimization)。
- 效果類似于
#include guard idiom
,后者通常采用預(yù)處理宏來防止多次包含同一文件。 - 該編譯指令還有助于避免違反單一定義原則(要求所有模板、類型、函數(shù)和對(duì)象在代碼中的定義不得超過一個(gè))。
- 如果要將代碼移植到不支持該編譯指令的編譯器平臺(tái),則建議使用
#include guard idiom
。
示例代碼
// header.h
#pragma once
// Code placed here is included only once per translation unit
// header.h
// Demonstration of the #include guard idiom.
// Note that the defined symbol can be arbitrary.
#ifndef HEADER_H_ // equivalently, #if !defined HEADER_H_
#define HEADER_H_
// Code placed here is included only once per translation unit
#endif // HEADER_H_
optimize
語(yǔ)法
#pragma optimize( "[optimization-list]", {on | off} )
作用
指定編譯器對(duì)函數(shù)的優(yōu)化類型。
備注
- 該編譯指令必須放在函數(shù)體外部,并且對(duì)該指令設(shè)定后的函數(shù)生效。
- on和off用于打開或關(guān)閉optimization-list指定的優(yōu)化類型。
- optimization-list可以是下表中顯示的0個(gè)或多個(gè)參數(shù),與/O編譯選項(xiàng)參數(shù)一樣。
Parameter(s) | Type of optimization |
---|---|
g | Enable global optimizations. |
s or t | Specify short or fast sequences of machine code. |
y | Generate frame pointers on the program stack. |
- 指令特殊形式:optimization-list為""空字符串。
示例代碼
// 等價(jià)于/Os編譯選項(xiàng)
#pragma optimize( "ts", on )
// 關(guān)閉前面指定的優(yōu)化選項(xiàng)
#pragma optimize( "", off )
.
.
.
// 重新打開編譯優(yōu)化選項(xiàng)
#pragma optimize( "", on )
pack
語(yǔ)法
#pragma pack( [ show ] | [ push | pop ] [, identifier ] , n )
作用
指定結(jié)構(gòu)、聯(lián)合和類成員的對(duì)齊方式。
備注
- 緊湊壓縮一個(gè)類就是將類成員變量在內(nèi)存中緊挨著存放,也就是說某些成員變量的對(duì)齊邊界比該變量類型的默認(rèn)情況要小。比如UINT64類型默認(rèn)情況是8字節(jié)對(duì)齊的,通過pack指令可以指定為4字節(jié)對(duì)齊。
- pack指令提供了數(shù)據(jù)聲明級(jí)別的控制,而/Zp編譯提供了模塊級(jí)別的控制。
- pack指令對(duì)設(shè)定之后的第一個(gè)struct,union或者class聲明生效,該指令對(duì)定義無效。
- 不帶參數(shù)的pack指令默認(rèn)將/Zp設(shè)置的對(duì)齊字節(jié)數(shù)作為n參數(shù)。當(dāng)/Zp未設(shè)定時(shí),默認(rèn)8字節(jié)對(duì)齊。
- 修改數(shù)據(jù)結(jié)構(gòu)的對(duì)齊方式之后,可以減少內(nèi)存的使用,但可能會(huì)降低性能或由于未對(duì)齊訪問引起硬件異常,可以通過SetErrorMode來修改異常行為模式。
- show: 可選參數(shù),通過警告消息顯示當(dāng)前的對(duì)齊方式。
- push: 可選參數(shù),將當(dāng)前對(duì)齊方式壓入編譯堆棧,設(shè)置后續(xù)對(duì)齊方式為n,n未指定則采用當(dāng)前對(duì)齊方式。
- pop: 可選參數(shù),彈出編譯堆棧頂部的元素,如果n未設(shè)定,則將彈出的頂部元素作為新的對(duì)齊方式,否則對(duì)齊方式為n。例如:
#pragma pack(pop, 16)
。如果pop指令指定了identifer(如#pragma pack(pop, r1)
),則彈出r1之前包括r1的所有元素,并將新的棧頂元素作為對(duì)齊方式。如果未找到identifer標(biāo)示符,則忽略該指令。 - identifer: 可選參數(shù),指定壓入堆棧或彈出堆棧的標(biāo)示符。
- n: 可選參數(shù),指定用于對(duì)齊的值,單位為字節(jié)。有效值是1、2、4、8和16。
- 更多對(duì)齊信息請(qǐng)參閱__alignof,align,__unaligned,Examples of Structure Alignment。
示例代碼
// pragma_directives_pack.cpp
#include <stddef.h>
#include <stdio.h>
struct S {
int i; // size 4
short j; // size 2
double k; // size 8
};
#pragma pack(2)
struct T {
int i;
short j;
double k;
};
int main() {
printf("%zu ", offsetof(S, i));
printf("%zu ", offsetof(S, j));
printf("%zu\n", offsetof(S, k));
printf("%zu ", offsetof(T, i));
printf("%zu ", offsetof(T, j));
printf("%zu\n", offsetof(T, k));
}
0 4 8
0 4 6
// pragma_directives_pack_2.cpp
// compile with: /W1 /c
#pragma pack() // n defaults to 8; equivalent to /Zp8
#pragma pack(show) // warning C4810: value of pragma pack(show) == 8
#pragma pack(4) // n = 4
#pragma pack(show) // warning C4810: value of pragma pack(show) == 4
#pragma pack(push, r1, 16) // n = 16, pushed to stack
#pragma pack(show) // warning C4810: value of pragma pack(show) == 16
#pragma pack(pop, r1, 2) // n = 2 , stack popped
#pragma pack(show) // warning C4810: value of pragma pack(show) == 2
pointers_to_members
語(yǔ)法
#pragma pointers_to_members( pointer-declaration, [most-general-representation] )
作用
指定能否在類定義之前聲明指向類成員的指針,以及類成員是否控制指針大小以及如何解析類成員指針。
備注
- 該編譯指令功能等價(jià)于/vmx編譯選項(xiàng)或繼承關(guān)鍵字。
- pointer-declaration: 指定在關(guān)聯(lián)的函數(shù)定義之前還是之后聲明指向成員的指針。參數(shù)如下:
參數(shù) | 注釋 |
---|---|
full_generality | 生成安全(有時(shí)并非最佳)代碼。如果在關(guān)聯(lián)的類定義之前聲明指向成員的任何指針,請(qǐng)使用full_generality。此參數(shù)始終使用most-general-representation參數(shù)所指定的指針表示形式。 等價(jià)于/vmg。 |
best_case | 對(duì)指向成員的所有指針使用best-case representation參數(shù)生成安全的最佳代碼。 要求在聲明指向類成員的指針之前定義此類。 系統(tǒng)默認(rèn)為best_case。 |
*3. most-general-representation: 指定了最小指針表示形式,用于編譯器可以安全地引用指向編譯單元中的類成員的任何指針。參數(shù)如下:
參數(shù) | 注釋 |
---|---|
single_inheritance | 最常見的表示形式為單一繼承(指向成員函數(shù)的指針)。如果類定義(已為其聲明指向成員的指針)的繼承模型為多重繼承或虛擬繼承,則會(huì)導(dǎo)致出現(xiàn)錯(cuò)誤。 |
multiple_inheritance | 最常見的表示形式為多重繼承(指向成員函數(shù)的指針)。如果類定義(已為其聲明指向成員的指針)的繼承模型為虛擬繼承,則會(huì)導(dǎo)致出現(xiàn)錯(cuò)誤。 |
virtual_inheritance | 最常見的表示形式為虛擬繼承(指向成員函數(shù)的指針)。不會(huì)導(dǎo)致錯(cuò)誤。這是#pragma pointers_to_members(full_generality) 的默認(rèn)參數(shù)。 |
注意:建議將該編譯指令放在要使用的源文件中,并且放置在所有
#include
之后。避免影響其它源文件。
示例代碼
// Specify single-inheritance only
#pragma pointers_to_members( full_generality, single_inheritance )
pop_macro
語(yǔ)法
#pragma pop_macro( "macro_name" )
作用
將macro_name宏的值設(shè)置為堆棧頂部的存放該宏值。
備注
- 使用pop_macro之前必須先使用push_macro。
示例代碼
// pragma_directives_pop_macro.cpp
// compile with: /W1
#include <stdio.h>
#define X 1
#define Y 2
int main() {
printf("%d",X);
printf("\n%d",Y);
#define Y 3 // C4005
#pragma push_macro("Y")
#pragma push_macro("X")
printf("\n%d",X);
#define X 2 // C4005
printf("\n%d",X);
#pragma pop_macro("X")
printf("\n%d",X);
#pragma pop_macro("Y")
printf("\n%d",Y);
}
1
2
1
2
1
3
push_macro
語(yǔ)法
#pragma push_macro(" macro_name ")
作用
將macro_name宏的值壓入堆棧頂端。
備注
- 可以通過pop_macro恢復(fù)macro_name宏的值。
示例代碼
請(qǐng)參閱上述pop_macro。
region, endregion
語(yǔ)法
#pragma region name
#pragma endregion comment
作用
利用#pragma region
指定在使用Visual Studio的大綱功能時(shí)可展開或折疊的代碼塊。
備注
- comment: (可選參數(shù)),在代碼編輯器中顯示的注釋。
- name: (可選參數(shù)),區(qū)域名稱,此名稱將在代碼編輯器中顯示。
-
#pragma endregion
標(biāo)記#pragma region
塊的結(jié)尾。兩者必須一起配合使用。
示例代碼
// pragma_directives_region.cpp
#pragma region Region_1
void Test() {}
void Test2() {}
void Test3() {}
#pragma endregion Region_1
int main() {}
runtime_checks
語(yǔ)法
#pragma runtime_checks( "[runtime_checks]", {restore | off} )
作用
禁用或還原/RTC設(shè)置。
備注
- 在/RTC編譯選項(xiàng)未啟用時(shí)不能使用該編譯指令還原運(yùn)行時(shí)檢查。舉例:如果未指定/RTCs編譯選項(xiàng),則指定
#pragma runtime_checks( "s", restore)
也不會(huì)啟用堆棧幀校驗(yàn)。 - 該編譯指令必須放在函數(shù)體外部,而且在該指令之后的第一個(gè)函數(shù)定義開始生效。
- retore和off分別代表打開和關(guān)閉指定的runtime_checks。參數(shù)取值如下所示:
參數(shù) | 運(yùn)行時(shí)檢查的類型 |
---|---|
s | 啟用堆棧(幀)校驗(yàn)。 |
c | 提示某個(gè)數(shù)值向較小數(shù)據(jù)類型賦值時(shí)會(huì)導(dǎo)致數(shù)據(jù)丟失。 |
u | 提示某個(gè)變量在定義之前被使用。 |
*4. 上表中的參數(shù)與/RTC編譯選項(xiàng)的參數(shù)相同,例如,#pragma runtime_checks( "sc", restore )
。
*5. 特殊形式:參數(shù)runtime_checks為空字符串(""),對(duì)應(yīng)功能如下:
a. off: 禁用上表中的運(yùn)行時(shí)錯(cuò)誤檢查。
b. restore: 重置運(yùn)行時(shí)錯(cuò)誤檢查為/RTC編譯選項(xiàng)中指定的類型。
示例代碼
#pragma runtime_checks( "", off )
.
.
.
#pragma runtime_checks( "", restore )
更多信息請(qǐng)參閱:RTC Sample
section
語(yǔ)法
#pragma section( "section-name" [, attributes] )
作用
在obj文件中創(chuàng)建一個(gè)段。
備注
- 此處segment和section的概念是等價(jià)的。
- 一旦定義了一個(gè)段,將在編譯的剩余部分生效,但是必須通過__declspec(allocate)來指定段信息,否則將沒有數(shù)據(jù)存放在該段。
- section-name: 必須參數(shù),指定段名。該名不能與標(biāo)準(zhǔn)段名沖突。參見/SECTION查看不能使用的段名。
- attributes: 可選參數(shù),指定段屬性,各個(gè)屬性間用逗號(hào)分隔。可選屬性如下所示:
屬性 | 注釋 |
---|---|
read | 可讀 |
write | 可寫 |
execute | 可執(zhí)行 |
shared | 共享 |
nopage | 不可分頁(yè),對(duì)于win32設(shè)備驅(qū)動(dòng)程序很有用 |
nocahe | 不可分頁(yè),對(duì)于win32設(shè)備驅(qū)動(dòng)程序很有用 |
discard | 可丟棄,對(duì)于win32設(shè)備驅(qū)動(dòng)程序很有用 |
remove | 非常駐內(nèi)存,僅適用于虛擬設(shè)備驅(qū)動(dòng)程序(VxD)。 |
示例代碼
// pragma_section.cpp
#pragma section("mysec",read,write)
int j = 0; // 存放在數(shù)據(jù)段,因?yàn)闆]有使用__declspec(allocate)聲明
__declspec(allocate("mysec"))
int i = 0; // 存放在mysec段
int main(){}
setlocale
語(yǔ)法
#pragma setlocale( "[locale-string]" )
作用
定義在轉(zhuǎn)換寬字符常量和字符串時(shí)使用的區(qū)域設(shè)置(國(guó)家/地區(qū)和語(yǔ)言)。
備注
- 由于編譯可能在不同的區(qū)域設(shè)置環(huán)境下進(jìn)行,而不同區(qū)域?qū)⒍嘧止?jié)轉(zhuǎn)換為寬字符的算法可能存在差異,因此可以使用setlocale來指定編譯時(shí)的區(qū)域設(shè)置。這樣可以保證寬字符能夠以正確的格式保存。
- locale-string的默認(rèn)值是
""
。 - "C"區(qū)域設(shè)置會(huì)將字符串中的每個(gè)字符作為wchar_t(unsigned short)映射到"C"區(qū)域設(shè)置的值。
- 其它有效的參數(shù)是語(yǔ)言字符串列表中的區(qū)域選項(xiàng)。
示例代碼
#pragma setlocale("dutch")
能否處理指定的語(yǔ)言字符串取決于計(jì)算機(jī)是否支持對(duì)應(yīng)的代碼頁(yè)(code page)和語(yǔ)言ID。
strict_gs_check
語(yǔ)法
#pragma strict_gs_check([push,] on )
#pragma strict_gs_check([push,] off )
#pragma strict_gs_check(pop)
作用
提供加強(qiáng)型的安全檢測(cè)。
備注
- 指示編譯器在函數(shù)堆棧中插入隨機(jī)Cookie以便于檢測(cè)某些類別的基于堆棧的緩沖區(qū)溢出。
- 默認(rèn)情況下,/GS(緩沖區(qū)安全檢查)編譯選項(xiàng)不會(huì)為所有函數(shù)插入Cookie進(jìn)行檢測(cè)。更多詳細(xì)信息請(qǐng)參閱/GS(緩沖區(qū)安全檢查)
- 必須啟動(dòng)/GS編譯選項(xiàng)后才能使用strict_gs_check編譯指令。
- 該編譯指令一般用于存在潛在危害的數(shù)據(jù)的代碼模塊。
- 該編譯指令的攻擊性較強(qiáng),可以應(yīng)用于可能不需要保護(hù)的函數(shù),但是為了盡可能降低對(duì)應(yīng)用程序的影響,它通常會(huì)進(jìn)行優(yōu)化。
- 即使使用了該編譯指令,也要盡可能編寫安全的代碼,確保代碼中不存在緩沖區(qū)溢出。
示例代碼
// pragma_strict_gs_check.cpp
// compile with: /c
#pragma strict_gs_check(on)
void ** ReverseArray(void **pData,
size_t cData)
{
// *** This buffer is subject to being overrun!! ***
void *pReversed[20];
// Reverse the array into a temporary buffer
for (size_t j = 0, i = cData; i ; --i, ++j)
// *** Possible buffer overrun!! ***
pReversed[j] = pData[i];
// Copy temporary buffer back into input/output buffer
for (size_t i = 0; i < cData ; ++i)
pData[i] = pReversed[i];
return pData;
}
vtordisp
語(yǔ)法
#pragma vtordisp([push,] n)
#pragma vtordisp(pop)
#pragma vtordisp()
#pragma vtordisp([push,] {on | off})
作用
控制構(gòu)造/析構(gòu)偏移成員是否包含vtordisp隱藏字段。
備注
- push: 將當(dāng)前的vtordisp設(shè)置值壓入內(nèi)部編譯堆棧,并將新的vtordisp設(shè)置為n。如果未指定n的值,則不改變vtordisp的設(shè)置。
- pop: 將內(nèi)部編譯堆棧頂?shù)脑貜棾觯⑵湓O(shè)置為新的vtordisp設(shè)置。
- n: 指定vtordisp設(shè)置的值。可以是0,1或2,分別對(duì)應(yīng)于/vd0,/vd1和/vd2三個(gè)編譯選項(xiàng)。更多信息請(qǐng)參閱/vd(禁用構(gòu)造偏移)。
- on: 等價(jià)于
#pragma vtordisp(1)
。 - off: 等價(jià)于
#pragma vtordisp(0)
。 - 該編譯指令只能用于具有虛擬基類的代碼。產(chǎn)生vtordisp的條件如下:
a. 虛繼承中派生類重寫了基類的虛函數(shù)。
b. 派生類在構(gòu)造函數(shù)或析構(gòu)函數(shù)中通過虛基類的指針調(diào)用了重寫的基類函數(shù)。 - 該編譯指令會(huì)影響它之后類的對(duì)象模型。功能等價(jià)于/vd0,/vd1和/vd2編譯選項(xiàng),但是作用范圍不同。編譯選項(xiàng)作用于整個(gè)模塊,編譯指令的作用范圍根據(jù)設(shè)置的打開與關(guān)閉相關(guān)。
- 默認(rèn)設(shè)置為on(1),在必要時(shí)啟用vtordisp字段。
- 設(shè)置為2時(shí)將對(duì)所有具有虛函數(shù)的虛基類啟用vtordisp字段。
- vtordisp(2)可以確保dynamic_cast在部分構(gòu)造的對(duì)象上正常工作。更多信息請(qǐng)參閱編譯器警告(等級(jí) 1)C4436。
#pragma vtordisp(push, 2)
class GetReal : virtual public VBase { ... };
#pragma vtordisp(pop)
warning
語(yǔ)法
#pragma warning(
warning-specifier
:
warning-number-list [; warning-specifier : warning-number-list...] )
#pragma warning( push[ ,n ] )
#pragma warning( pop )
作用
選擇性修改編譯警告消息行為。
備注
- warning-specifier: 警告描述符,同一編譯指令中可以指定多個(gè),有效參數(shù)如下所示。
警告描述符 | 注釋 |
---|---|
1, 2, 3, 4 | 指定警告級(jí)別。 同時(shí)會(huì)啟用默認(rèn)情況下處于關(guān)閉狀態(tài)的指定警告。 |
default | 重置警告級(jí)別為默認(rèn)值。 同時(shí)會(huì)啟用默認(rèn)情況下處于關(guān)閉狀態(tài)的指定警告。 警告將在其默認(rèn)存檔級(jí)別生成。有關(guān)詳細(xì)信息,請(qǐng)參閱默認(rèn)關(guān)閉的編譯器警告。 |
disable | 禁用指定的警告。 |
error | 將指定警告報(bào)告為錯(cuò)誤。 |
once | 只顯示一次指定的警告消息。 |
suppress | 將當(dāng)前警告設(shè)置壓入堆棧,禁用下一行的指定警告,然后彈出警告堆棧,重置警告設(shè)置。 |
*2. warning-number-list: 參數(shù)可包含多個(gè)警告編號(hào)。
// 簡(jiǎn)寫
#pragma warning( disable : 4507 34; once : 4385; error : 164 )
// 等價(jià)于下面指令
// Disable warning messages 4507 and 4034.
#pragma warning( disable : 4507 34 )
// Issue warning 4385 only once.
#pragma warning( once : 4385 )
// Report warning 4164 as an error.
#pragma warning( error : 164 )
*3. 編譯器會(huì)將0-999區(qū)間的告警編號(hào)默認(rèn)加上4000,變成4000-4999。
*4. 在函數(shù)左大括號(hào)已經(jīng)生效的警告狀態(tài)在函數(shù)體其余部分也生效。
*5. 4700-4900區(qū)間內(nèi)的警告與代碼生成相關(guān),使用warning編譯指令修改大于4699的警告狀態(tài)會(huì)在函數(shù)體末尾之后生效。
// pragma_warning.cpp
// compile with: /W1
#pragma warning(disable:4700)
void Test() {
int x;
int y = x; // no C4700 here
#pragma warning(default:4700) // C4700 enabled after Test ends
}
int main() {
int x;
int y = x; // C4700
}
函數(shù)體中只有最后一個(gè)warning編譯指令會(huì)在函數(shù)體末尾生效。
*6. push: 保存每個(gè)警告的當(dāng)前警告狀態(tài)并壓入編譯棧,設(shè)置警告級(jí)別為n。
*7. pop:彈出壓入編譯棧的最后一個(gè)警告狀態(tài),同時(shí)撤銷push和pop之間的所有修改,還原每個(gè)警告的狀態(tài)。
#pragma warning( push )
#pragma warning( disable : 4705 )
#pragma warning( disable : 4706 )
#pragma warning( disable : 4707 )
// Some code
#pragma warning( pop )
pop會(huì)將每個(gè)警告(包括 4705、4706 和 4707)的狀態(tài)還原為其在代碼開頭的狀態(tài)。
*8. 編寫頭文件時(shí)可以使用push和pop來確保外部對(duì)警告狀態(tài)的修改不會(huì)影響到當(dāng)前文件。
#pragma warning( push, 3 )
// Declarations/definitions
#pragma warning( pop )
注意:要在文件開頭使用push,在文件末尾使用pop。
后記
終于總結(jié)完了,原來計(jì)劃是花幾天的晚上時(shí)間來整理就夠了,但是真正開始整理之后發(fā)現(xiàn)工作量遠(yuǎn)比預(yù)估的要大,斷斷續(xù)續(xù)差不多用了一周多時(shí)間,分析了一下主要的耗時(shí)有下面幾部分:
- 有些指令從來沒用過,需要查閱其它資料來熟悉和理解它。
- 理解MSDN的英文講解相對(duì)較容易,但是要把一些英文專業(yè)術(shù)語(yǔ)用中文表述出來卻需要反復(fù)斟酌一下,有種只可意會(huì),不可言傳的感覺,哈哈~
- 各個(gè)指令提供的示例代碼需要一些時(shí)間來調(diào)試和理解。
最后吐槽一下markdown的語(yǔ)法,一旦插入表格,后續(xù)的有序列表就會(huì)重新編號(hào),在網(wǎng)上看到好多人都遇到一樣的情況,最后用了*加數(shù)字的方式進(jìn)行處理,但是看著感覺還是有點(diǎn)怪怪的。