古詩詞大全網 - 成語故事 - 預處理指令#pragma db code是什麽意思?

預處理指令#pragma db code是什麽意思?

壹、作用是設定編譯器的狀態或者是指示編譯器完成壹些特定的動作。#pragma指令對每個編譯器給出了壹個方法,在保持與C和 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號警告行為到默認狀態

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

#pragma warning(push) // 保存所有警告信息的現有的警告狀態

#pragma warning(push,n) // 保存所有警告信息的現有的警告狀態,並設置全局報警級別為n

#pragma warning(pop) // 恢叢 鵲木 孀刺 趐ush和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文件中所在的數據段。如果未指定參數,初始化變量將放置在默認數據段.data中,有如下用法:

#pragma data_seg("Shared") // 定義了數據段"Shared",其中有兩個變量a和b

int a = 0; // 存儲在數據段"Shared"中

int b; // 存儲在數據段".bss"中,因為沒有初始化

#pragma data_seg() // 表示數據段"Shared"結束,該行代碼為可選的

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

#pragma data_seg("Shared")

int j = 0; // 存儲在數據段"Shared"中

#pragma data_seg(push, stack1, "Shared2") //定義數據段Shared2,並將該記錄賦予別名stack1,然後放入內部編譯器棧中

int l = 0; // 存儲在數據段"Shared2"中

#pragma data_seg(pop, stack1) // 從內部編譯器棧中彈出記錄,直到彈出stack1,如果沒有stack1,則不做任何操作

int m = 0; // 存儲在數據段"Shared"中,如果沒有上述pop段,則該變量將儲在數據段"Shared2"中

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

void func1() { // 默認存儲在代碼段.text中

}

#pragma code_seg(".my_data1")

void func2() { // 存儲在代碼段.my_data1中

}

#pragma code_seg(push, r1, ".my_data2")

void func3() { // 存儲在代碼段.my_data2中

}

#pragma code_seg(pop, r1)

void func4() { // 存儲在代碼段.my_data1中

}

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

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

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

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

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

#pragma pack(pop) //將內部編譯器棧頂的記錄彈出,並將其作為當前的內存對齊方式

#pragma pack(pop,4) //將內部編譯器棧頂的記錄彈出,並將4作為當前的內存對齊方式

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

8.#pragma comment。將壹個註釋記錄放置到對象文件或可執行文件中。

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

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

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

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

如果默認庫和附加庫的次序是需要區別的,使用/Zl編譯開關可防止默認庫放到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至65535;如果沒有指定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對該符號進行的移除操作。

(4)/MANIFESTDEPENDENCY:manifest_dependency

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

直接在命令行運行/MANIFESTDEPENDENCY

通過#pragma comment

(5)/MERGE:from=to

/MERGE選項將第壹個段(from)與第二個段(to)進行聯合,並將聯合後的段命名為to的名稱。

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

/MERGE選項對於創建VxDs和重寫編譯器生成的段名非常有用。

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

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

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

段(section)中包含代碼或數據。與節區(segment)不同的是,段(section)是沒有大小限制的連續內存塊。有些段中的代碼或數據是妳的程序直接定義和使用的,而有些數據段是鏈接器和庫管理器(lib.exe)創建的,並且包含了對操作系統來說很重要的信息。

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

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

.arch

.bss

.data

.edata

.idata

.pdata

.rdata

.reloc

.rsrc

.sbss

.sdata

.srdata

.text

.xdata

為段指定壹個或多個屬性。屬性不是大小寫敏感的。對於壹個段,妳必須將希望它具有的屬性都進行指定;如果某個屬性未指定,則認為是不具備這個屬性。如果妳未指定R,W或E,則已存在的讀,寫或可執行狀態將不發生改變。

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

E:可執行的

R:可讀取的

W:可寫的

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

D:可廢棄的

K:不可緩存的

P:不可分頁的

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

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

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

user:放置壹個常規註釋到壹個對象文件中,該選項是被linker忽略的。

9.#pragma section。創建壹個段。

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

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

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

read:可讀取的

write:可寫的

execute:可執行的

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

nopage:不可分頁的,主要用於Win32的設備驅動程序中

nocache:不可緩存的,主要用於Win32的設備驅動程序中

discard:可廢棄的,主要用於Win32的設備驅動程序中

remove:非內存常駐的,僅用於虛擬設備驅動(VxD)中

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

在創建了段之後,還要使用__declspec(allocate)將代碼或數據放入段中。

例如:

//pragma_section.cpp

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

int j = 0;

__declspec(allocate("mysec"))

int i = 0;

int main(){}

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

10.#pragma push_macro與#pragma pop_macro。前者將指定的宏壓入棧中,相當於暫時存儲,以備以後使用;後者將棧頂的宏出棧,彈出的宏將覆蓋當前名稱相同的宏。例如:

#include

#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