日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

#pragma预处理命令

發(fā)布時間:2024/4/11 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 #pragma预处理命令 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

#pragma可以說是C++中最復雜的預處理指令了,下面是最常用的幾個#pragma指令:

#pragma comment(lib,"XXX.lib")

表示鏈接XXX.lib這個庫,和在工程設置里寫上XXX.lib的效果一樣。

#pragma comment(linker,"/ENTRY:main_function")

表示指定鏈接器選項/ENTRY:main_function

#pragma once

表示這個文件只被包含一次

#pragma warning(disable:4705)

表示屏蔽警告4705

?

????? C和C++程序的每次執(zhí)行都支持其所在的主機或操作系統(tǒng)所具有的一些獨特的特點。例如,有些程序需要精確控制數(shù)據(jù)存放的內(nèi)存區(qū)域或控制某個函

數(shù)接收的參數(shù)。#pragma為編譯器提供了一種在不同機器和操作系統(tǒng)上編譯以保持C和C++完全兼容的方法。#pragma是由機器和相關的操作系統(tǒng)定義

的,通常對每個編譯器來說是不同的。

??????? 如果編譯器遇到不認識的pragma指令,將給出警告信息,然后繼續(xù)編譯。Microsoft C and C++ 的編譯器可識別以下指令:alloc_text,

auto_inline,bss_seg,check_stack,code_seg,comment,component,conform,const_seg,data_seg,deprecated,

fenv_access,float_control,fp_contract,function,hdrstop,include_alias,init_seg,inline_depth,inline_recursion,intrinsic,

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。其中conform,init_seg,

pointers_to_members,vtordisp僅被C++編譯器支持。

?

?????? 以下是常用的pragma指令的詳細解釋。

1.#pragma once。保證所在文件只會被包含一次,它是基于磁盤文件的,而#ifndef則是基于宏的。

?

2.#pragma warning。允許有選擇性的修改編譯器的警告消息的行為。有如下用法:

#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(default:176)???? // 重置編譯器的176號警告行為到默認狀態(tài)?

同時這個pragma warning也支持如下格式,其中n代表一個警告等級(1---4):?????????????

#pragma warning(push)?? // 保存所有警告信息的現(xiàn)有的警告狀態(tài)??

#pragma warning(push,n) // 保存所有警告信息的現(xiàn)有的警告狀態(tài),并設置全局報警級別為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)。

3.#pragma hdrstop。表示預編譯頭文件到此為止,后面的頭文件不進行預編譯。BCB可以預編譯頭文件以 加快鏈接的速度,但如果所有頭文件都進

行預編譯又可能占太多磁盤空間,所以使用這個選項排除一些頭文 件。

?

4.#pragma message。在標準輸出設備中輸出指定文本信息而不結束程序運行。用法如下:

#pragma message("消息文本")。當編譯器遇到這條指令時就在編譯輸出窗口中將“消息文本”打印出來。

?

5.#pragma data_seg。一般用于DLL中,它能夠設置程序中的初始化變量在obj文件中所在的數(shù)據(jù)段。如果未指定參數(shù),初始化變量將放置在默認數(shù)

據(jù)段.data中,有如下用法:

1: #pragma data_seg("Shared") // 定義了數(shù)據(jù)段"Shared",其中有兩個變量a和b 2: int a = 0; // 存儲在數(shù)據(jù)段"Shared"中 3: int b; // 存儲在數(shù)據(jù)段".bss"中,因為沒有初始化 4: #pragma data_seg() // 表示數(shù)據(jù)段"Shared"結束,該行代碼為可選的

對變量進行專門的初始化是很重要的,否則編譯器將把它們放在普通的未初始化數(shù)據(jù)段中而不是放在shared中。如上述的變量b其實是放在了未初始化數(shù)

據(jù)段.bss中。

1: #pragma data_seg("Shared") 2: int j = 0; // 存儲在數(shù)據(jù)段"Shared"中 3: #pragma data_seg(push, stack1, "Shared2") //定義數(shù)據(jù)段Shared2,并將該記錄賦予別名stack1,然后放入內(nèi)部編譯器棧中 4: int l = 0; // 存儲在數(shù)據(jù)段"Shared2"中 5: #pragma data_seg(pop, stack1) // 從內(nèi)部編譯器棧中彈出記錄,直到彈出stack1,如果沒有stack1,則不做任何操作 6: int m = 0; // 存儲在數(shù)據(jù)段"Shared"中,如果沒有上述pop段,則該變量將儲在數(shù)據(jù)段"Shared2"中

?

6.#pragma code_seg。它能夠設置程序中的函數(shù)在obj文件中所在的代碼段。如果未指定參數(shù),函數(shù)將放置在默認代碼段.text中,有如下用法:

1: void func1() { // 默認存儲在代碼段.text中 2: } 3: 4: #pragma code_seg(".my_data1") 5: 6: void func2() { // 存儲在代碼段.my_data1中 7: } 8: 9: #pragma code_seg(push, r1, ".my_data2") 10: 11: void func3() { // 存儲在代碼段.my_data2中 12: } 13: 14: #pragma code_seg(pop, r1) 15: 16: void func4() { // 存儲在代碼段.my_data1中 17: }

7.#pragma pack。用來改變編譯器的字節(jié)對齊方式。常規(guī)用法為:

#pragma pack(n)?? //將編譯器的字節(jié)對齊方式設為n,n的取值一般為1、2、4、8、16,一般默認為8

#pragma pack(show) //以警告信息的方式將當前的字節(jié)對齊方式輸出

#pragma pack(push) //將當前的字節(jié)對齊方式放入到內(nèi)部編譯器棧中

#pragma pack(push,4) //將字節(jié)對齊方式4放入到內(nèi)部編譯器棧中,并將當前的內(nèi)存對齊方式設置為4

#pragma pack(pop) //將內(nèi)部編譯器棧頂?shù)挠涗洀棾?#xff0c;并將其作為當前的內(nèi)存對齊方式

#pragma pack(pop,4) //將內(nèi)部編譯器棧頂?shù)挠涗洀棾?#xff0c;并將4作為當前的內(nèi)存對齊方式

#pragma pack(pop,r1) //r1為自定義的標識符,將內(nèi)部編譯器中的記錄彈出,直到彈出r1,并將r1的值作為當前的內(nèi)存對齊方式;如果r1不存在,當

不做任何操作

一個例子:

以如下結構為例: struct {
?????????????????? char a;
?????????????????? WORD b;
?????????????????? DWORD c;
?????????????????? char d;
????????????????? }
在Windows默認結構大小: sizeof(struct) = 4+4+4+4=16;
與#pragma pack(4)一樣
若設為 #pragma pack(1), 則結構大小: sizeof(struct) = 1+2+4+1=8;
若設為 #pragma pack(2), 則結構大小: sizeof(struct) = 2+2+4+2=10;
在#pragma pack(1)時:空間是節(jié)省了,但訪問速度降低了;
有什么用處???
在系統(tǒng)通訊中,如和硬件設備通信,和其他的操作系統(tǒng)進行通信時等,必須保證雙方的一致性。

?

8.#pragma comment。將一個注釋記錄放置到對象文件或可執(zhí)行文件中。

其格式為:#pragma comment( comment-type [,"commentstring"] )。其中,comment-type是一個預定義的標識符,指定注釋的類型,應該是compiler,exestr,lib,linker,user之一。

compiler:放置編譯器的版本或者名字到一個對象文件,該選項是被linker忽略的。

exestr:在以后的版本將被取消。

lib:放置一個庫搜索記錄到對象文件中,這個類型應該與commentstring(指定Linker要搜索的lib的名稱和路徑)所指定的庫類型一致。在對象文件中,庫的名字跟在默認搜索記錄后面;linker搜索這個這個庫就像你在命令行輸入這個命令一樣。你可以在一個源文件中設置多個庫搜索記錄,它們在obj

文件中出現(xiàn)的順序與在源文件中出現(xiàn)的順序一樣。

如果默認庫和附加庫的次序是需要區(qū)別的,使用/Zl編譯開關可防止默認庫放到object模塊中。

linker:指定一個連接選項,這樣就不用在命令行輸入或者在開發(fā)環(huán)境中設置了。只有下面的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]

    使用該選項,可以從程序?qū)С龊瘮?shù)以便其他程序可以調(diào)用該函數(shù),也可以導出數(shù)據(jù)。通常在DLL中定義導出。

    entryname是調(diào)用程序要使用的函數(shù)或數(shù)據(jù)項的名稱。ordinal為導出表的索引,取值范圍在1至65535;如果沒有指定ordinal,則LINK將分配一個。

    NONAME關鍵字只將函數(shù)導出為序號,沒有entryname。DATA 關鍵字指定導出項為數(shù)據(jù)項。客戶程序中的數(shù)據(jù)項必須用extern __declspec

    (dllimport)來聲明。

    有三種導出定義的方法,按照建議的使用順序依次為:

  • 源代碼中的__declspec(dllexport)
  • .def文件中的EXPORTS語句
  • LINK命令中的/EXPORT規(guī)范
  • 所有這三種方法可以用在同一個程序中。LINK在生成包含導出的程序時還要創(chuàng)建導入庫,除非在生成過程中使用了.exp 文件。

    LINK使用標識符的修飾形式。編譯器在創(chuàng)建obj文件時修飾標識符。如果entryname以其未修飾的形式指定給鏈接器(與其在源代碼中一樣),則LINK

    將試圖匹配該名稱。如果無法找到唯一的匹配名稱,則LINK發(fā)出錯誤信息。當需要將標識符指定給鏈接器時,請使用Dumpbin工具獲取該標識符的修飾

    名形式。

    ?

    (3)/INCLUDE:symbol

    /INCLUDE選項通知鏈接器將指定的符號添加到符號表。若要指定多個符號,請在符號名稱之間鍵入逗號(,)、分號(;)或空格。在命令行上,對每個符號需指定一次/INCLUDE:symbol。

    鏈接器通過將包含符號定義的對象添加到程序來解析symbol。該功能對于添加不會鏈接到程序的庫對象非常有用。

    用該選項所指定的符號將覆蓋通過/OPT:REF對該符號進行的移除操作。

    ?

    (4)/MANIFESTDEPENDENCY:manifest_dependency

    /MANIFESTDEPENDENCY允許你指定位于manifest文件的<dependency>段的屬性。/MANIFESTDEPENDENCY信息可以通過下面兩種方式傳遞給LINK:

    直接在命令行運行/MANIFESTDEPENDENCY

    通過#pragma comment

    ?

    (5)/MERGE:from=to

    /MERGE選項將第一個段(from)與第二個段(to)進行聯(lián)合,并將聯(lián)合后的段命名為to的名稱。

    如果第二個段不存在,LINK將段(from)重命名為to的名稱。

    /MERGE選項對于創(chuàng)建VxDs和重寫編譯器生成的段名非常有用。

    ?

    (6)/SECTION:name,[[!]{DEKPRSW}][,ALIGN=#]

    /SECTION選項用來改變段的屬性,當指定段所在的obj文件編譯的時候重寫段的屬性集。

    可移植的可執(zhí)行文件(PE)中的段(section)與新可執(zhí)行文件(NE)中的節(jié)區(qū)(segment)或資源大致相同。

    段(section)中包含代碼或數(shù)據(jù)。與節(jié)區(qū)(segment)不同的是,段(section)是沒有大小限制的連續(xù)內(nèi)存塊。有些段中的代碼或數(shù)據(jù)是你的程序直接定義和

    使用的,而有些數(shù)據(jù)段是鏈接器和庫管理器(lib.exe)創(chuàng)建的,并且包含了對操作系統(tǒng)來說很重要的信息。

    /SECTION選項中的name是大小寫敏感的。

    不要使用以下名稱,因為它們與標準名稱會沖突,例如,.sdata是RISC平臺使用的。

    .arch

    .bss

    .data

    .edata

    .idata

    .pdata

    .rdata

    .reloc

    .rsrc

    .sbss

    .sdata

    .srdata

    .text

    .xdata

    為段指定一個或多個屬性。屬性不是大小寫敏感的。對于一個段,你必須將希望它具有的屬性都進行指定;如果某個屬性未指定,則認為是不具備這個屬

    性。如果你未指定R,W或E,則已存在的讀,寫或可執(zhí)行狀態(tài)將不發(fā)生改變。

    要對某個屬性取否定意義,只需要在屬性前加感嘆號(!)。

    E:可執(zhí)行的

    R:可讀取的

    W:可寫的

    S:對于載入該段的鏡像的所有進程是共享的

    D:可廢棄的

    K:不可緩存的

    P:不可分頁的

    注意K和P是表示否定含義的。

    PE文件中的段如果沒有E,R或W屬性集,則該段是無效的。

    ALIGN=#選項讓你為一個具體的段指定對齊值。

    user:放置一個常規(guī)注釋到一個對象文件中,該選項是被linker忽略的。

    ?

    9.#pragma section。創(chuàng)建一個段。

    其格式為:#pragma section( "section-name" [, attributes] )

    section-name是必選項,用于指定段的名字。該名字不能與標準段的名字想沖突。可用/SECTION查看標準段的名稱列表。

    attributes是可選項,用于指定段的屬性。可用屬性如下,多個屬性間用逗號(,)隔開:

    read:可讀取的

    write:可寫的

    execute:可執(zhí)行的

    shared:對于載入該段的鏡像的所有進程是共享的

    nopage:不可分頁的,主要用于Win32的設備驅(qū)動程序中

    nocache:不可緩存的,主要用于Win32的設備驅(qū)動程序中

    discard:可廢棄的,主要用于Win32的設備驅(qū)動程序中

    remove:非內(nèi)存常駐的,僅用于虛擬設備驅(qū)動(VxD)中

    如果未指定屬性,默認屬性為read和write。

    在創(chuàng)建了段之后,還要使用__declspec(allocate)將代碼或數(shù)據(jù)放入段中。

    例如:

    //pragma_section.cpp

    #pragma section("mysec",read,write)

    int j = 0;

    __declspec(allocate("mysec"))

    int i = 0;

    int main(){}

    該例中, 創(chuàng)建了段"mysec",設置了read,write屬性。但是j沒有放入到該段中,而是放入了默認的數(shù)據(jù)段中,因為它沒有使用__declspec(allocate)進

    行聲明;而i放入了該段中,因為使用__declspec(allocate)進行了聲明。

    ?

    10.#pragma push_macro與#pragma pop_macro。前者將指定的宏壓入棧中,相當于暫時存儲,以備以后使用;后者將棧頂?shù)暮瓿鰲?#xff0c;彈出的宏將覆蓋當前名稱相同的宏。例如:

    1: #include <stdio.h> 2: #define X 1 3: #define Y 2 4: 5: int main() { 6: printf("%d",X); 7: printf("\n%d",Y); 8: #define Y 3 // C4005 9: #pragma push_macro("Y") 10: #pragma push_macro("X") 11: printf("\n%d",X); 12: #define X 2 // C4005 13: printf("\n%d",X); 14: #pragma pop_macro("X") 15: printf("\n%d",X); 16: #pragma pop_macro("Y") 17: printf("\n%d",Y); 18: }

    輸出結果:

    1

    2

    1

    2

    1

    3

    總結

    以上是生活随笔為你收集整理的#pragma预处理命令的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。