#pragma編譯指令大全(上)

前言

最近在學(xué)習(xí)#pragma編譯指令相關(guān)的知識(shí),網(wǎng)上也有很多文章介紹各個(gè)指令的用法,但是在網(wǎng)上搜到的對(duì)#pragma總結(jié)的文章都不夠全面,看到最多的一個(gè)版本也就包含了20多條指令。所以我就通過查閱MSDN官方的說明文檔,然后根據(jù)自己的理解對(duì)現(xiàn)有的#pragma編譯指令進(jìn)行了梳理和總結(jié)。希望能夠幫助大家對(duì)#pragma系列指令有更好的理解。

由于全文太長,無法放在一片文章發(fā)表,所以就拆分成上下兩部分

綜述

#pragma指令是每個(gè)編譯器在保留C和C++語言的整體兼容性時(shí)提供不同機(jī)器和操作系統(tǒng)特定的功能。編譯指令是機(jī)器或操作系統(tǒng)特有的,并且不同的編譯器通常存在差異。
語法如下:
#pragma token_string // token_string為參數(shù)

“#”必須是編譯指令的第一個(gè)非空白字符;而“#”和“pragma”之間可以存在任意個(gè)數(shù)的空白符。在#pragma后面,寫任何編譯器能夠作為預(yù)處理符號(hào)分析的文本。#pragma的參數(shù)類似于宏擴(kuò)展。如果參數(shù)無法識(shí)別,編譯器會(huì)拋出一個(gè)警告后繼續(xù)編譯。示例代碼如下:

#pragma once    // 正確
  #pragma once  // 正確
# pragma once   // 正確
;#pragma once   // 錯(cuò)誤 
ps: error C2014: preprocessor command must start as first nonwhite space

為了提供新的預(yù)處理功能,或者為編譯程序提供由實(shí)現(xiàn)定義的信息,編譯指示可以用在一個(gè)條件語句內(nèi)。

請(qǐng)參閱Pragma 指令和 __Pragma 關(guān)鍵字

C和C++編譯器可以識(shí)別下列編譯指令。

row1 row2 row3 row4
alloc_text auto_inline bss_seg check_stack
code_seg comment component conform
const_seg data_seg deprecated detect_mismatch
fenv_access float_control fp_contract function
hdrstop include_alias init_seg inline_depth
inline_recursion intrinsic loop make_public
managed message omp once optimize
pack pointers_to_members pop_macro push_macro
region, endregion runtime_checks section setlocale
strict_gs_check unmanaged vtordisp warning

alloc_text

語法

#pragma alloc_text( "textsection", function1, ... )

作用

命名特定函數(shù)駐留的代碼段。

備注

  1. 必須出現(xiàn)在函數(shù)聲明和函數(shù)定義之間。
  2. 不處理C++成員函數(shù)或重載函數(shù)。它僅能應(yīng)用在以C連接方式聲明的函數(shù)(用extern "C"連接)。如果將該指令運(yùn)用在具有C++連接方式的函數(shù)時(shí),將出現(xiàn)編譯錯(cuò)誤。
  3. 由于函數(shù)尋址不支持__based形式,所以需要通過該編譯指令來指定代碼段。textsection指定的名字應(yīng)該由雙引號(hào)括起來。
  4. 引用的函數(shù)必須與該指令處于同一模塊中,否則可能無法捕獲編譯器將未定義的函數(shù)編譯到不同的代碼段中的錯(cuò)誤,即使程序通常還能正常運(yùn)行,但是函數(shù)并沒有分配到指定的代碼段中。
  5. 該編譯指令不能用在一個(gè)函數(shù)體內(nèi)部。

auto_inline

語法

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

作用

打開(on)或關(guān)閉(off)編譯器將普通函數(shù)自動(dòng)轉(zhuǎn)換為inline函數(shù)的功能。

備注

  1. 不能出現(xiàn)在函數(shù)定義內(nèi)部,需要寫在函數(shù)定義之前或之后。
  2. 將在其出現(xiàn)以后的第一個(gè)函數(shù)定義開始起作用。
  3. 對(duì)顯式的inline函數(shù)不起作用。

bss_seg

語法

#pragma bss_seg( [ [ { push | pop }, ] [ identifier, ] ] [ "segment-name" [, "segment-class" ] )

作用

指定obj文件中存放未初始化變量的段。

備注

  1. obj文件可以通過dumpbin來查看。
  2. obj中存放未初始化變量的默認(rèn)段為.bss。
  3. 在一些情況下將未初始化變量存儲(chǔ)在一個(gè)段中可以提高加載速度。
  4. 不帶參數(shù)的bss_egg將段重置為.bss
  5. push: 將一條段記錄壓入編譯堆棧,可以帶identifier和segment-name參數(shù)。
  6. pop: 將編譯堆棧頂?shù)挠涗洀棾觥?/li>
  7. identifer: 可選參數(shù),當(dāng)使用push時(shí)指定壓入編譯堆棧的記錄標(biāo)示符,當(dāng)使用pop時(shí),彈出從棧頂?shù)皆摌?biāo)示符記錄之間的所有元素。它可以使一條pop指令彈出多條push記錄。
  8. segment-name: 段名,當(dāng)使用pop指令之后,彈出的段名將作為新的激活段。
  9. segment-class: 段類,用于兼容C++2.0之前的版本,已廢棄。

代碼示例

// pragma_directive_bss_seg.cpp  
int i;  // stored in .bss  
#pragma bss_seg(".my_data1")  
int j;  // stored in "my_data1"  

#pragma bss_seg(push, stack1, ".my_data2")     
int l;  // stored in "my_data2"  

// pop stack1 from stack  
#pragma bss_seg(pop, stack1)   
int m;  // stored in "stack_data1"  
  
int main() {}  

check_stack

語法

#pragma check_stack([ {on | off}] )
#pragma check_stack{+ | –}

作用

打開(on/+)或關(guān)閉(off/-)棧檢查。

備注

  1. check_stack在無參情況下棧檢查恢復(fù)到默認(rèn)行為,詳細(xì)情況見編譯器參考
  2. 該編譯指令將在其出現(xiàn)之后的第一個(gè)函數(shù)開始生效。
  3. 棧檢查不是宏或者inline函數(shù)的一部分。
  4. #pragma check_stack和/Gs選項(xiàng)的互相作用情況如下所示。
Syntax Compiled with/Gs option? Action
#pragma check_stack( ) or #pragma check_stack Yes Turns off stack checking for functions that follow
#pragma check_stack( ) or #pragma check_stack No Turns on stack checking for functions that follow
#pragma check_stack(on)or #pragma check_stack + Yes or No Turns on stack checking for functions that follow
#pragma check_stack(off)or #pragma check_stack – Yes or No Turns off stack checking for functions that follow

表格中前面兩條的Action總感覺弄反了,待確認(rèn)


code_seg

語法

#pragma code_seg( [ [ { push | pop}, ] [ identifier, ] ] [ "segment-name" [, "segment-class" ] )

作用

指定obj文件中存放函數(shù)的代碼段。

備注

  1. obj文件中存放代碼的默認(rèn)段是.text
  2. 其它用法與bss_seg類似。

代碼示例

// pragma_directive_code_seg.cpp
void func1() {} // stored in .text

#pragma code_seg(".my_data1")
void func2() {} // stored in my_data1

#pragma code_seg(push, r1, ".my_data2")
void func3() {} // stored in my_data2
}

#pragma code_seg(pop, r1)      
void func4() {} // stored in my_data1
}

int main() {}

comment

語法

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

作用

將描述記錄嵌入到目標(biāo)文件或可執(zhí)行文件中。

備注

  1. comment-type是一個(gè)預(yù)定義標(biāo)識(shí)符,用于指定注釋的類型,是compiler,exestr,lib,linker和user五個(gè)標(biāo)示符之一。
  2. commentstring是可選字段,用于為一些comment-type提供附加的信息。因?yàn)閏ommentstring是一個(gè)字符串,所以它適用字符串的所有規(guī)則,例如換碼字符、嵌入的引號(hào)(")和聯(lián)接。
compiler
  • 將編譯器名稱和版本號(hào)信息存放到目標(biāo)文件中,連接器(linker)會(huì)忽略該描述記錄。
  • 如果compiler提供一個(gè)commentstring參數(shù),編譯程序?qū)⑸梢粋€(gè)警告。
    #pragma comment( compiler )
exestr
  • 將commentstring存放到目標(biāo)文件中去,并且在連接時(shí)存放到可執(zhí)行文件去中。
  • 可執(zhí)行文件運(yùn)行后不會(huì)加載該字符串到內(nèi)存,但是該字符串可以被能夠在文件中搜索可打印字符串的程序檢索到。
  • 該描述記錄的一個(gè)用處是在可執(zhí)行文件中嵌入版本號(hào)或者類似的信息。
    #pragma comment( exestr, "test" )
lib
  • 將靜態(tài)鏈接庫信息放置到目標(biāo)文件中去。
  • 該描述類型必須有commentstring參數(shù),其中包含靜態(tài)鏈接庫的名稱或路徑。
  • 該庫名放在目標(biāo)文件中默認(rèn)庫搜索信息之后,linker會(huì)像在命令行中輸入一樣搜索該庫名。
  • 可以在一個(gè)源文件中放置多個(gè)庫搜索信息,并且按照它們出現(xiàn)在源文件中的順序存放在目標(biāo)文件中。
    #pragma comment( lib, "emapi" )
linker
  • 在目標(biāo)文件中放置連接程序選項(xiàng)。
  • 可以用它指定連接程序選項(xiàng)來代替在Project Setting對(duì)話框中Link頁內(nèi)的選項(xiàng)。例如,你可以指定/include選項(xiàng)以強(qiáng)制包含一個(gè)符號(hào):
    #pragma comment(linker, "/include:__mySymbol")
  • 只有下列選項(xiàng)可用于linker標(biāo)識(shí)符
    /DEFAULTLIB
    /EXPORT
    /INCLUDE
    /MANIFESTDEPENDENCY
    /MERGE
    /SECTION
user
  • 將普通描述信息存放在目標(biāo)文件中。commentstring參數(shù)包含描述的文本。linker將忽略該描述信息。
  • commentstring可以嵌套連接字符串宏。
    #pragma comment( user, "Compiled on " __DATE__ " at " __TIME__ )

component

語法

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

作用

控制對(duì)源文件中瀏覽信息或依賴信息的收集。

備注

瀏覽器(Browser)
  • 可以打開或關(guān)閉收集,也可以指定在收集信息時(shí)忽略特定名稱或類型。
  • 若要打開瀏覽信息的收集,必須先啟用瀏覽信息功能。
  • references選項(xiàng)可以有也可以沒有name參數(shù)。使用沒有name參數(shù)的references選項(xiàng)將打開或者關(guān)閉引用信息的收集(然而繼續(xù)收集其它瀏覽信息)。
  • 使用有name和off參數(shù)的references選項(xiàng)將阻止從瀏覽信息窗口中出現(xiàn)引用到的名字。用這個(gè)語法將忽略你不感興趣的名字和類型從而減少瀏覽信息文件的大小。
  • 若要防止預(yù)處理器擴(kuò)展name(如將NULL擴(kuò)展到0),請(qǐng)使用引號(hào)將其包含。
// 關(guān)閉收集瀏覽信息
#pragma component(browser, off)

// 關(guān)閉收集引用信息
#pragma component(browser, off, references)

// 關(guān)閉收集DWORD類型的引用信息 
#pragma component(browser, off, references, DWORD)
// 打開收集DWORD類型的引用信息
#pragma component(browser, on, references, DWORD)

// 防止預(yù)處理器擴(kuò)展name(如:NULL擴(kuò)展為0)
#pragma component(browser, off, references, "NULL") 
最小化重建(Minimal Rebuild)
  • Visual C++的最小化重建功能要求編譯器創(chuàng)建并保存需要大量磁盤空間的C++類依賴信息。
  • 使用#pragma component(minrebuild,off)關(guān)閉信息收集。
  • 使用#pragma component(minrebuild,on)重新打開依賴信息。
減少類型信息(Reduce Type Information)
  • mintypeinfo選項(xiàng)將減少指定區(qū)域的調(diào)試信息。此信息的量相當(dāng)大,會(huì)影響.pdb和.obj文件。
  • 不能在mintypeinfo區(qū)域中調(diào)試類和結(jié)構(gòu)。
  • 使用mintypeinfo選項(xiàng)可幫助避免以下警告:
    LINK : warning LNK4018: too many type indexes in PDB "filename", discarding subsequent type information

更多詳細(xì)內(nèi)容,請(qǐng)參閱Enable Minimal Rebuild(/Gm)編譯程序選項(xiàng)。


conform

語法

#pragma conform(name [, show ] [, on | off ] [ [, push | pop ] [, identifier ] ] )

作用

指定/Zc:forScope編譯器選項(xiàng)的運(yùn)行時(shí)行為。

備注

  1. name:指定要修改的編譯器選項(xiàng)的名稱。 唯一有效的name為forScope。
  2. show(可選): 將name的當(dāng)前設(shè)置(true或false)在編譯期間以警告消息的方式顯示。
  3. on、off(可選): 將name設(shè)置為on將啟用/Zc:forScope編譯器選項(xiàng)。默認(rèn)值為off。
  4. push(可選): 將name的當(dāng)前值推送到內(nèi)部編譯器堆棧。如果指定identifier,則可為要推送到堆棧的name指定on或off值。
  5. pop(可選):將name的值設(shè)置為位于內(nèi)部編譯器堆棧頂部的值,然后彈出堆棧。 如果使用pop指定 identifier,則堆棧將彈回,直到它找到具有identifier的記錄(也會(huì)彈出);堆棧上的下一記錄中的 name的當(dāng)前值將變?yōu)閚ame的新值。如果使用不在堆棧上的記錄中的identifier指定pop,則將忽略 pop。
  6. identifier(可選):可以與push或pop命令包含在一起。如果使用了identifier,則還可以使用 on或off說明符。

示例代碼

// pragma_directive_conform.cpp
// compile with: /W1
// C4811 expected
#pragma conform(forScope, show)
#pragma conform(forScope, push, x, on)
#pragma conform(forScope, push, x1, off)
#pragma conform(forScope, push, x2, off)
#pragma conform(forScope, push, x3, off)
#pragma conform(forScope, show)
#pragma conform(forScope, pop, x1)
#pragma conform(forScope, show)

int main() {}

const_seg

語法

#pragma const_seg( [ [ { push | pop}, ] [ identifier, ] ] [ "segment-name" [, "segment-class" ] )

作用

指定obj文件中存放const變量的段。

備注

  1. obj文件中存放const變量的默認(rèn)段為.rdata。
  2. 某些const變量(如標(biāo)量)會(huì)自動(dòng)內(nèi)斂到代碼流中。
  3. 內(nèi)斂代碼將不會(huì)存放在.rdata中。
  4. 在const_seg中定義需要?jiǎng)討B(tài)初始化的對(duì)象會(huì)導(dǎo)致未定義的行為。
  5. 不帶參數(shù)的#pragma const_seg會(huì)將段重置為.rdata。

示例代碼

// pragma_directive_const_seg.cpp  
// compile with: /EHsc  
#include <iostream>  
  
const int i = 7;               // inlined, not stored in .rdata  
const char sz1[]= "test1";     // stored in .rdata  
  
#pragma const_seg(".my_data1")  
const char sz2[]= "test2";     // stored in .my_data1  
  
#pragma const_seg(push, stack1, ".my_data2")  
const char sz3[]= "test3";     // stored in .my_data2  
  
#pragma const_seg(pop, stack1) // pop stack1 from stack  
const char sz4[]= "test4";     // stored in .my_data1  
  
int main() {  
    using namespace std;  
   // const data must be referenced to be put in .obj  
   cout << sz1 << endl;  
   cout << sz2 << endl;  
   cout << sz3 << endl;  
   cout << sz4 << endl;  
}

data_seg

語法

#pragma data_seg( [ [ { push | pop }, ] [ identifier, ] ] [ "segment-name" [, "segment-class" ] )

作用

指定obj文件中存放初始化變量的數(shù)據(jù)段。

備注

  1. obj文件中存放初始化變量的默認(rèn)段為.data
  2. 未初始化的變量被視為初始化為零并且存儲(chǔ)在.bss中。
  3. 不帶參數(shù)的data_seg將段重置為.data

示例代碼

// pragma_directive_data_seg.cpp  
int h = 1;                     // stored in .data  
int i = 0;                     // stored in .bss  
#pragma data_seg(".my_data1")  
int j = 1;                     // stored in "my_data1"  
  
#pragma data_seg(push, stack1, ".my_data2")     
int l = 2;                     // stored in "my_data2"  
  
#pragma data_seg(pop, stack1)  // pop stack1 off the stack  
int m = 3;                     // stored in "stack_data1"  
  
int main() {}  

deprecated

語法

#pragma deprecated( identifier1 [,identifier2, ...] ) 

作用

指示函數(shù)、類型或任何其他標(biāo)識(shí)符已廢棄。

備注

  1. 當(dāng)編譯器遇到廢棄的符號(hào)時(shí),會(huì)拋出警告C4995。
  2. 可以廢棄宏名稱。但是需要將宏名稱包含在引號(hào)內(nèi),否則宏將展開。
  3. 可以使用deprecated __declspec廢棄重載函數(shù)。

示例代碼

// pragma_directive_deprecated.cpp  
// compile with: /W3  
#include <stdio.h>  
void func1(void) {} 
void func2(void) {}
  
int main() {  
   func1();  
   func2();  
   #pragma deprecated(func1, func2)  
   func1();   // C4995  
   func2();   // C4995  
}

// pragma_directive_deprecated2.cpp  
// compile with: /W3  
#pragma deprecated(X)  
class X {  // C4995  
public:  
   void f(){}  
};  
  
int main() {  
   X x;   // C4995  
}  

detect_mismatch

語法

#pragma detect_mismatch( "name", "value"))

作用

將記錄放在一個(gè)對(duì)象中。 鏈接器將檢查這些記錄中的潛在不匹配項(xiàng)。

備注

  1. link項(xiàng)目時(shí),如果項(xiàng)目包含name相同但value不同的兩個(gè)對(duì)象,則linker將拋出錯(cuò)誤LNK2038
  2. 使用detect_mismatch可防止連接中存在不一致的對(duì)象文件。
  3. 名稱和值都是字符串,遵循轉(zhuǎn)義字符和連接的字符串規(guī)則。 同時(shí)區(qū)分大小寫,不能包含逗號(hào)、等號(hào)、引號(hào)或null字符。

示例代碼

// pragma_directive_detect_mismatch_a.cpp  
#pragma detect_mismatch("myLib_version", "9")  
int main ()  
{  
   return 0;  
}  
  
// pragma_directive_detect_mismatch_b.cpp  
#pragma detect_mismatch("myLib_version", "1")  

如果使用命令行 cl pragma_directive_detect_mismatch_a.cpp pragma_directive_detect_mismatch_b.cpp 編譯這兩個(gè)文件,則會(huì)收到錯(cuò)誤 LNK2038。


execution_character_set

語法

#pragma execution_character_set("target") 

作用

指定運(yùn)行時(shí)字符集。

備注

  1. target指定字符集名稱,目前只支持“utf-8”;
  2. 該指令在Visual Studio 2015 Updatae 2中廢棄了。建議使用編譯選項(xiàng)/execution-charset:utf-8/utf-8配合u8前綴來指定字符集。
  3. 默認(rèn)情況下編譯器采用系統(tǒng)當(dāng)前字符集對(duì)源文件進(jìn)行編碼。
  4. 在未指定編碼集的情況下在不同的電腦上進(jìn)行編譯可能會(huì)引起編譯警告和錯(cuò)誤。

示例代碼

#pragma execution_character_set("utf-8") 

fenv_access

語法

#pragma fenv_access [ON | OFF]

作用

禁用(ON)或啟用(OFF)可能更改標(biāo)記測試和模式更改的優(yōu)化。

備注

  1. 默認(rèn)情況下,fenv_access為OFF。
  2. 有關(guān)浮點(diǎn)行為的詳細(xì)信息,請(qǐng)參閱/fp(指定浮點(diǎn)行為)
  3. fenv_access的優(yōu)化類型有如下幾種。
    a. 全局公共子表達(dá)式消除
    b. 代碼移動(dòng)
    c. 常量折疊

示例代碼

// pragma_directive_fenv_access_x86.cpp  
// compile with: /O2  
// processor: x86  
#include <stdio.h>  
#include <float.h>   
#include <errno.h>  
#pragma fenv_access (on)  
  
int main() {  
   double z, b = 0.1, t = 0.1;  
   unsigned int currentControl;  
   errno_t err;  
  
   err = _controlfp_s(&currentControl, _PC_24, _MCW_PC);  
   if (err != 0) {  
      printf_s("The function _controlfp_s failed!\n");  
      return -1;  
   }  
   z = b * t;  
   printf_s ("out=%.15e\n",z);  
}  

out=9.999999776482582e-003

注釋掉#pragma fenv_access (on)之后,由于編譯器執(zhí)行編譯時(shí)計(jì)算,這個(gè)過程未使用控制模式,因此輸出不同。

out=1.000000000000000e-002


float_control

語法

float_control( value,setting [push] | push | pop )

作用

指定函數(shù)的浮點(diǎn)行為。

備注

  1. value: 可以是precise或except。
  2. setting: 可以是on或off。
  3. 如果vaule是precise,則設(shè)置precise和except為setting的值。
  4. except只有在precise為on的情況下設(shè)置為on。
  5. push: 將當(dāng)前的float_control設(shè)置壓入編譯器內(nèi)部堆棧。
  6. pop: 從內(nèi)部編譯器堆棧頂部移除float_control設(shè)置,使其成為新的float_control設(shè)置。
  7. 當(dāng)except打開時(shí),無法關(guān)閉float_control precise。同樣,當(dāng)fevn_access打開時(shí),無法關(guān)閉precise。

示例代碼

// 從嚴(yán)格模式轉(zhuǎn)換到快速模式
#pragma float_control(except, off)  
#pragma fenv_access(off)  
#pragma float_control(precise, off)  
// The following line is needed on Itanium processors  
#pragma fp_contract(on)

// 從快速模式轉(zhuǎn)換到嚴(yán)格模式
#pragma float_control(precise, on)  
#pragma fenv_access(on)  
#pragma float_control(except, on)  
// The following line is needed on Itanium processors.  
#pragma fp_contract(off)

// 捕獲浮點(diǎn)數(shù)溢出異常
// pragma_directive_float_control.cpp  
// compile with: /EHa  
#include <stdio.h>  
#include <float.h>  
  
double func( ) {  
   return 1.1e75;  
}  
  
#pragma float_control (except,on)  
  
int main( ) {  
   float u[1];  
   unsigned int currentControl;  
   errno_t err;  
  
   err = _controlfp_s(&currentControl, ~_EM_OVERFLOW, _MCW_EM);  
   if (err != 0)  
      printf_s("_controlfp_s failed!\n");  
  
   try  {  
      u[0] = func();  
      printf_s ("Fail");     
      return(1);  
   }   
  
   catch (...)  {  
      printf_s ("Pass");  
      return(0);  
   }  
}   

fp_contract

語法

#pragma fp_contract [ON | OFF]

作用

決定是否使用浮點(diǎn)數(shù)縮寫形式。

備注

  1. 默認(rèn)情況下,fp_contract處于打開狀態(tài)。

示例代碼

// pragma_directive_fp_contract.cpp  
// compile with: /O2  
#include <stdio.h>  
#include <float.h>  
  
#pragma fp_contract (off)   
  
int main() {  
   double z, b, t;  
  
   for (int i = 0; i < 10; i++) {  
      b = i * 5.5;  
      t = i * 56.025;  
      _set_controlfp(_PC_24, _MCW_PC);  
  
      z = t * i + b;  
      printf_s ("out=%.15e\n", z);  
   }  
}  

out=0.000000000000000e+000
out=6.152500152587891e+001
out=2.351000061035156e+002
out=5.207249755859375e+002
out=9.184000244140625e+002
out=1.428125000000000e+003
out=2.049899902343750e+003
out=2.783724853515625e+003
out=3.629600097656250e+003

out=4.587524902343750e+003


function

語法

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

作用

指定對(duì)function參數(shù)列表中的函數(shù)進(jìn)行顯示函數(shù)調(diào)用。

備注

  1. 如果使用intrinsic編譯指令(或/Oi編譯選項(xiàng))指示編譯生成內(nèi)斂函數(shù)(內(nèi)斂函數(shù)如同嵌入代碼一樣生成,不作為一個(gè)函數(shù)調(diào)用),則可以使用function編譯指令來實(shí)現(xiàn)顯示函數(shù)調(diào)用。
  2. 一旦設(shè)定了function編譯指令,它將在包含指定函數(shù)的第一個(gè)函數(shù)定義中生效。該效果持續(xù)到源文件結(jié)尾或遇到instrsic編譯指令指定相同的函數(shù)。
  3. function僅能在函數(shù)的外部使用- 全局級(jí)別。

示例代碼

// pragma_directive_function.cpp  
#include <ctype.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
  
// use intrinsic forms of memset and strlen  
#pragma intrinsic(memset, strlen)  
  
// Find first word break in string, and set remaining  
// chars in string to specified char value.  
char *set_str_after_word(char *string, char ch) {  
   int i;  
   int len = strlen(string);  /* NOTE: uses intrinsic for strlen */  
  
   for(i = 0; i < len; i++) {  
      if (isspace(*(string + i)))   
         break;  
   }  
  
   for(; i < len; i++)   
      *(string + i) = ch;  
  
   return string;  
}  
  
// do not use strlen intrinsic  
#pragma function(strlen)  
  
// Set all chars in string to specified char value.  
char *set_str(char *string, char ch) {  
   // Uses intrinsic for memset, but calls strlen library function  
   return (char *) memset(string, ch, strlen(string));  
}  
  
int main() {  
   char *str = (char *) malloc(20 * sizeof(char));  
  
   strcpy_s(str, sizeof("Now is the time"), "Now is the time");  
   printf("str is '%s'\n", set_str_after_word(str, '*'));  
   printf("str is '%s'\n", set_str(str, '!'));  
}  

str is 'Now************'
str is '!!!!!!!!!!!!!!!'


hdrstop

語法

#pragma hdrstop [( "filename" )]

作用

提供對(duì)預(yù)編譯文件名和編譯狀態(tài)的保存位置的額外控制。

備注

  1. filename是要使用或創(chuàng)建的預(yù)編譯頭文件的名稱(取決于是否指定/Yu/Yc)。
  2. 如果filename不包含路徑說明,則假定預(yù)編譯頭文件與源文件處于同一目錄中。
  3. 當(dāng)用/Yc編譯時(shí),如果C或C++文件中包含了一個(gè)hdrstop編譯指令,則編譯器保存編譯指令之前的編譯狀態(tài)。編譯指令之后的編譯狀態(tài)不被保存。
  4. filename指定了預(yù)編譯狀態(tài)保存的文件名。文件名是字符串,因此受C/C++的字符串約束。必須通過引號(hào)同時(shí)使用轉(zhuǎn)義符(反斜杠)來指定目錄名稱。例如:
    #pragma hdrstop( "c:\\projects\\include\\myinc.pch" )
  5. 預(yù)編譯頭文件的名稱根據(jù)以下規(guī)則按優(yōu)先順序決定:
    a. /Fp編譯選項(xiàng)的參數(shù)
    b. #pragma hdrstop 的 filename 參數(shù)
    c. 擴(kuò)展名為.PCH的源文件基名稱
  6. 如果/Yc和/Yu兩個(gè)編譯選項(xiàng)以及hdrstop編譯指令都未指定文件名,則將源文件的基名稱用作預(yù)編譯頭文件的名稱。
  7. 可以使用預(yù)處理命令來執(zhí)行宏替換,如下所示:
#define INCLUDE_PATH "c:\\progra~`1\\devstsu~1\\vc\\include\\"  
#define PCH_FNAME "PROG.PCH"  
.  
.  
.  
#pragma hdrstop( INCLUDE_PATH PCH_FNAME ) 
  1. hdrstop必須出現(xiàn)在任何數(shù)據(jù)或函數(shù)聲明/定義的外部。
  2. hdrstop必須在源文件而不是頭文件中指定。

示例代碼

#include <windows.h>                 // Include several files  
#include "myhdr.h"  
  
__inline Disp( char *szToDisplay )   // Define an inline function  
{  
    ...                              // Some code to display string  
}  
#pragma hdrstop

include_alias

語法

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

作用

指定shot_filename用于long_filename的別名。

備注

  1. 有些文件系統(tǒng)允許長度超過8.3 FAT文件系統(tǒng)限制的文件名。因?yàn)檩^長的頭文件名的前8個(gè)字符可能不是唯一的,因此編譯器不能簡單的將較長的名稱截?cái)酁?.3。
  2. 當(dāng)編譯器遇到long_filename字符串是,都將用short_filename進(jìn)行替換,并改為查找shot_filename頭文件。
  3. 該指令必須在#include指令之前出現(xiàn)。
// 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"
  1. 別名必須要完全符合規(guī)范,包括大小寫,拼寫,雙引號(hào)和尖括號(hào)的使用。
  2. include_alias對(duì)文件名進(jìn)行簡單的字符串匹配,不會(huì)對(duì)文件名進(jìn)行其它校驗(yàn)。下面代碼將不執(zhí)行別名替換操作。
#pragma include_alias("mymath.h", "math.h")  
#include "./mymath.h"  
#include "sys/mymath.h" 
  1. include_alias不會(huì)替換/Yu和/Yc以及hdrstop指令參數(shù)的頭文件名。
// 編譯選項(xiàng)
/YcAppleSystemHeaderStop.h
// 頭文件包含
#include <AppleSystemHeaderStop.h>
  1. 可以使用include_alias將任何頭文件名映射到另一個(gè)頭文件名。
#pragma include_alias( "api.h", "c:\version1.0\api.h" )  
#pragma include_alias( <stdio.h>, <newstdio.h> )  
#include "api.h"  
#include <stdio.h>
  1. 不要將用雙引號(hào)括起來的文件名與用尖括號(hào)括起的文件名混淆使用。例如,給定上述兩個(gè)#pragma include_alias指令,編譯器將不對(duì)下列 #include 指令執(zhí)行任何替換:
#include <api.h>  
#include "stdio.h"
  1. 以下指令將報(bào)錯(cuò)。
#pragma include_alias(<header.h>, "header.h")  // Error
  1. 錯(cuò)誤消息中提示的文件名(或作為預(yù)定義的 FILE 宏的值的文件名)是文件在執(zhí)行替換后的名稱。
#pragma include_alias( "VeryLongFileName.H", "myfile.h" )  
#include "VeryLongFileName.H"

myfile.h(15) : error C2059 : syntax error

  1. include_alias不支持傳遞性。
#pragma include_alias( "one.h", "two.h" )  
#pragma include_alias( "two.h", "three.h" )  
#include "one.h"

編譯器將搜索文件two.h而不是three.h。


init_seg

語法

#pragma init_seg({ compiler | lib | user | "section-name" [, func-name]} )

作用

指定影響啟動(dòng)代碼的執(zhí)行順序的關(guān)鍵字或代碼段。

備注

  1. 本節(jié)中segment和section的含義是可互換的。
  2. 由于全局靜態(tài)對(duì)象的初始化可能涉及代碼執(zhí)行,因此,必須指定一個(gè)關(guān)鍵字用于確定對(duì)象的構(gòu)造時(shí)間。
  3. init_seg在動(dòng)態(tài)鏈接庫(DLL)或需要初始化的庫中使用特別重要。
  4. init_seg的選項(xiàng)如下:
    a. compiler: 保留給Microsoft C運(yùn)行庫初始化使用,該組中的對(duì)象會(huì)優(yōu)先構(gòu)造。
    b. lib: 用于第三方類庫的初始化,該組中的對(duì)象在compiler之后構(gòu)造。
    c. user: 可供任何用戶使用,該組中的對(duì)象最后構(gòu)造。
    d. section-name: 顯式指定初始化的段名。該段中的對(duì)象通過顯式構(gòu)造函數(shù)構(gòu)造,并且對(duì)象地址存放在該段中。該段中存放著用于初始化該段之后的全局變量的輔助函數(shù)指針。
    e. func-name: 指定程序退出時(shí)替換atexit的函數(shù)。在自己的退出函數(shù)中可以控制不同模塊的析構(gòu)順序。這個(gè)函數(shù)必須具有和atexit函數(shù)相同的形式:
    int funcname(void (__cdecl *)(void));
  5. 可以通過顯式指定段名稱來延遲對(duì)象的初始化,但是必須為每個(gè)靜態(tài)對(duì)象顯式調(diào)用構(gòu)造函數(shù)進(jìn)行初始化。
  6. func-name不需要用引號(hào)包含。
  7. 各個(gè)對(duì)象存放在由xxx_seg編譯指令指定的段中。
  8. 默認(rèn)情況下,init_seg部分是只讀的,如果段名稱是.CRT,則編譯器會(huì)自動(dòng)將段屬性修改為只讀,即使段標(biāo)志為讀寫。
  9. 每個(gè)源文件中只能出現(xiàn)一次init_seg。
  10. 模塊中聲明的對(duì)象不會(huì)由C運(yùn)行時(shí)自動(dòng)初始化,需要我們主動(dòng)調(diào)用。如果對(duì)象沒有用戶定義的構(gòu)造函數(shù),系統(tǒng)會(huì)生成默認(rèn)構(gòu)造函數(shù),但是還是需要我們主動(dòng)調(diào)用。

示例代碼

// pragma_directive_init_seg.cpp  
#include <stdio.h>  
#pragma warning(disable : 4075)  
  
typedef void (__cdecl *PF)(void);  
int cxpf = 0;   // number of destructors we need to call  
PF pfx[200];    // pointers to destructors.  
  
int myexit (PF pf) {  
   pfx[cxpf++] = pf;  
   return 0;  
}  
  
struct A {  
   A() { puts("A()"); }  
   ~A() { puts("~A()"); }  
};

struct B {  
   B() { puts("B()"); }  
   ~B() { puts("~B()"); }  
};

struct C {  
   C() { puts("C()"); }  
   ~C() { puts("~C()"); }  
}; 
  
// ctor & dtor called by CRT startup code   
// because this is before the pragma init_seg  
A aaaa;   
  
// The order here is important.  
// Section names must be 8 characters or less.  
// The sections with the same name before the $  
// are merged into one section. The order that  
// they are merged is determined by sorting  
// the characters after the $.  
// InitSegStart and InitSegEnd are used to set  
// boundaries so we can find the real functions  
// that we need to call for initialization.  
  
#pragma section(".mine$a", read)  
__declspec(allocate(".mine$a")) const PF InitSegStart = (PF)1;  
  
#pragma section(".mine$z",read)  
__declspec(allocate(".mine$z")) const PF InitSegEnd = (PF)1;  
  
// The comparison for 0 is important.  
// For now, each section is 256 bytes. When they  
// are merged, they are padded with zeros. You  
// can't depend on the section being 256 bytes, but  
// you can depend on it being padded with zeros.  
  
void InitializeObjects () {  
   const PF *x = &InitSegStart;  
   for (++x ; x < &InitSegEnd ; ++x)  
      if (*x) (*x)();  
}  
  
void DestroyObjects () {  
   while (cxpf>0) {  
      --cxpf;  
      (pfx[cxpf])();  
   }  
}  
  
// by default, goes into a read only section  
#pragma init_seg(".mine$m", myexit)  
  
B bbbb;   
C cccc;  
  
int main () {  
   InitializeObjects();  
   DestroyObjects();  
}

A()
B()
C()
~C()
~B()
A()

剩余編譯指令內(nèi)容請(qǐng)閱讀#pragma編譯指令大全(下)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 接上一篇#pragma編譯指令大全(上) inline_depth 語法 作用 指定函數(shù)的內(nèi)斂深度,超過深度n的內(nèi)...
    小豬啊嗚閱讀 9,836評(píng)論 2 5
  • 目錄 一.預(yù)處理的工作方式... 3 1.1.預(yù)處理的功能... 3 1.2預(yù)處理的工作方式... 3 二.預(yù)處理...
    朱森閱讀 1,553評(píng)論 0 2
  • C中的預(yù)編譯宏定義 2009-02-10 作者: infobillows 來源:網(wǎng)絡(luò) 在將一個(gè)C源程序轉(zhuǎn)換為可執(zhí)行...
    白水灬煮一切閱讀 1,741評(píng)論 0 5
  • linux資料總章2.1 1.0寫的不好抱歉 但是2.0已經(jīng)改了很多 但是錯(cuò)誤還是無法避免 以后資料會(huì)慢慢更新 大...
    數(shù)據(jù)革命閱讀 13,352評(píng)論 2 33
  • 綾羅綢扇綾羅鋪 默德芳人又一籌
    薔薇颯閱讀 276評(píng)論 0 1

友情鏈接更多精彩內(nèi)容