c語言預處理命令包括,c語言的預處理功能是指

本文目錄一覽:

常見的預處理命令有哪兩種?

很多小夥伴在自己寫代碼的時候,已經多次使用過include命令。使用庫函數之前,應該用include引入對應的頭文件。其實這種以#號開頭的命令稱為預處理命令。

C語言源文件要經過編譯、鏈接才能生成可執行程序:

1) 編譯(Compile)會將源文件(.c文件)轉換為目標文件。對於 VC/VS,目標文件後綴為.obj;對於GCC,目標文件後綴為.o。

編譯是針對單個源文件的,一次編譯操作只能編譯一個源文件,如果程序中有多個源文件,就需要多次編譯操作。

2) 鏈接(Link)是針對多個文件的,它會將編譯生成的多個目標文件以及系統中的庫、組件等合併成一個可執行程序。

關於編譯和鏈接的過程、目標文件和可執行文件的結構、.h 文件和 .c 文件的區別,我們將在後期專題中講解。

在實際開發中,有時候在編譯之前還需要對源文件進行簡單的處理。例如,我們希望自己的程序在 Windows 和 Linux 下都能夠運行,那麼就要在 Windows 下使用 VS 編譯一遍,然後在 Linux 下使用 GCC 編譯一遍。但是現在有個問題,程序中要實現的某個功能在 VS 和 GCC 下使用的函數不同(假設 VS 下使用 a(),GCC 下使用 b()),VS 下的函數在 GCC 下不能編譯通過,GCC 下的函數在 VS 下也不能編譯通過,怎麼辦呢?

這就需要在編譯之前先對源文件進行處理:如果檢測到是 VS,就保留 a() 刪除 b();如果檢測到是 GCC,就保留 b() 刪除 a()。

這些在編譯之前對源文件進行簡單加工的過程,就稱為預處理(即預先處理、提前處理)。

預處理主要是處理以開頭的命令,例如include stdio.h等。預處理命令要放在所有函數之外,而且一般都放在源文件的前面。

預處理是C語言的一個重要功能,由預處理程序完成。當對一個源文件進行編譯時,系統將自動調用預處理程序對源程序中的預處理部分作處理,處理完畢自動進入對源程序的編譯。

編譯器會將預處理的結果保存到和源文件同名的.i文件中,例如 main.c 的預處理結果在 main.i 中。和.c一樣,.i也是文本文件,可以用編輯器打開直接查看內容。

C語言提供了多種預處理功能,如宏定義、文件包含、條件編譯等,合理地使用它們會使編寫的程序便於閱讀、修改、移植和調試,也有利於模塊化程

關於C語言預處理命令

C程序的源代碼中可包括各種編譯指令,這些指令稱為預處理命令。雖然它們實際上不是C語言的一部分,但卻擴展了C程序設計的環境。本節將介紹如何應用預處理程序和注釋簡化程序開發過程,並提高程序的可讀性。ANSI標準定義的C語言預處理程序包括下列命令:

#define,#error,#include,#if,#else,#elif,#endif,#ifdef,#ifndef,#undef,#line,#pragma等。非常明顯,所有預處理命令均以符號#開頭,下面分別加以介紹。

一 #define

命令#define定義了一個標識符及一個串。在源程序中每次遇到該標識符時,均以定義的串代換它。ANSI標準將標識符定義為宏名,將替換過程稱為宏替換。命令的一般形式為:

#define identifier string

注意:

1該語句沒有分號。在標識符和串之間可以有任意個空格,串一旦開始,僅由一新行結束。

2宏名定義後,即可成為其它宏名定義中的一部分。

3 宏替換僅僅是以文本串代替宏標識符,前提是宏標識符必須獨立的識別出來,否則不進行替換。例如:

#define XYZ this is a tes

使用宏printf(“XYZ”);//該段不打印”this is a test”而打印”XYZ”。因為預編譯器識別出的是”XYZ”

4如果串長於一行,可以在該行末尾用一反斜杠’ \’續行。

#defineLONG_STRING”this is a very long\

string that is used as an example”

5 C語言程序普遍使用大寫字母定義標識符。

6 用宏代換代替實在的函數的一大好處是宏替換增加了代碼的速度,因為不存在函數調用的開銷。但增加速度也有代價:由於重複編碼而增加了程序長度。

二 #error

命令#error強迫編譯程序停止編譯,主要用於程序調試。

#error指令使預處理器發出一條錯誤消息,該消息包含指令中的文本.這條指令的目的就是在程序崩潰之前能夠給出一定的信息。

三 #include

命令#i nclude使編譯程序將另一源文件嵌入帶有#include的源文件,被讀入的源文件必須用雙引號或尖括號括起來。例如:

#include”stdio.h”或者#includestdio.h

這兩行代碼均使用C編譯程序讀入並編譯用於處理磁盤文件庫的子程序。

將文件嵌入#i nclude命令中的文件內是可行的,這種方式稱為嵌套的嵌入文件,嵌套層次依賴於具體實現。

如果顯式路徑名為文件標識符的一部分,則僅在那些子目錄中搜索被嵌入文件。否則,如果文件名用雙引號括起來,則首先檢索當前工作目錄。如果未發現文件,則在命令行中說明的所有目錄中搜索。如果仍未發現文件,則搜索實現時定義的標準目錄。

如果沒有顯式路徑名且文件名被尖括號括起來,則首先在編譯命令行中的目錄內檢索。如果文件沒找到,則檢索標準目錄,不檢索當前工作目錄。

四 條件編譯命令

有幾個命令可對程序源代碼的各部分有選擇地進行編譯,該過程稱為條件編譯。商業軟件公司廣泛應用條件編譯來提供和維護某一程序的許多顧客版本。

#if、#else,#elif及#endif

#if的一般含義是如果#if後面的常量表達式為true,則編譯它與#endif之間的代碼,否則跳過這些代碼。命令#endif標識一個#if塊的結束。

#if constant-expression

statement sequence

#endif

Eg:

#define MAX 91

#include iostream

using namespace std;

int main()

{

#if MAX 99

cout”MAX is bigger than 99″endl;

#elif MAX 90

cout”MAX is bigger than 90″endl;

#else

cout”MAX is smaller than 90″endl;

#endif

return 0;

}

跟在#if後面的表達式在編譯時求值,因此它必須僅含常量及已定義過的標識符,不可使用變量。表達式不許含有操作符sizeof(sizeof也是編譯時求值)。

#else命令的功能有點象C語言中的else;#else建立另一選擇(在#if失敗的情況下)。注意,#else屬於#if塊。

#elif命令意義與ELSE IF 相同,它形成一個if else-if階梯狀語句,可進行多種編譯選擇。#elif 後跟一個常量表達式。如果表達式為true,則編譯其後的代碼塊,不對其它#elif表達式進行測試。否則,順序測試下一塊。

#if expression

statement sequence

#elif expression1

statement sequence

#endif

在嵌套的條件編譯中#endif、#else或#elif與最近#if或#elif匹配。

# ifdef 和# ifndef

條件編譯的另一種方法是用#ifdef與#ifndef命令,它們分別表示”如果有定義”及”如果無定義”。# ifdef的一般形式是:

# ifdef macroname

statement sequence

#endif

#ifdef與#ifndef可以用於#if、#else,#elif語句中,但必須與一個#endif。

#define MAX 91

#include iostream

using namespace std;

int main()

{

#ifdef MAX

cout”hello,MAX!”endl;

#else

cout”where is MAX?”endl;

#endif

#ifndef LEO

cout”LEO is not defined”endl;

#endif

return 0;

}

命令#undef 取消其後那個前面已定義過有宏名定義。一般形式為:

#undef macroname

命令#line改變__LINE__與__FILE__的內容,它們是在編譯程序中預先定義的標識符。命令的基本形式如下:

#line number[“filename”]

其中的數字為任何正整數,可選的文件名為任意有效文件標識符。行號為源程序中當前行號,文件名為源文件的名字。命令#line主要用於調試及其它特殊應用。注意:在#line後面的數字標識從下一行開始的數字標識。

#line 100 “jia”

cout”#line change line and filename!”endl; //line 100

cout__LINE__endl; //101

cout__FILE__endl; //jia

五 #pragma

命令#pragma 為實現時定義的命令,它允許向編譯程序傳送各種指令。

#pragma的作用是設定編譯器的狀態或者是指示編譯器完成一些特定的動作。#pragma指令對每個編譯器給出了一個方法,在保持與C和C++語言完全兼容的情況下,給出主機或操作系統專有的特徵。依據定義,編譯指示是機器或操作系統專有的,且對於每個編譯器都是不同的。

其格式一般為: #Pragma Para

1 message 參數。

Message 參數能夠在編譯信息輸出窗口中輸出相應的信息,這對於源代碼信息的控制是非常重要的。其使用方法為:

#pragma message(“消息文本”)

當編譯器遇到這條指令時就在編譯輸出窗口中將消息文本打印出來。

當在程序中定義了許多宏來控制源代碼版本的時候,自己有可能都會忘記有沒有正確的設置這些宏,此時可以用這條指令在編譯的時候就進行檢查。假設希望判斷自己有沒有在源代碼的什麼地方定義了_X86這個宏可以用下面的方法

#ifdef _X86

#pragma message(“_X86 macro activated!”)

#endif

當定義了_X86這個宏以後,應用程序在編譯時就會在編譯輸出窗口裡顯示“_

X86 macro activated!”。就不會因為不記得自己定義的一些特定的宏而抓耳撓腮了。

2 code_seg 參數。

格式如:

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

它能夠設置程序中函數代碼存放的代碼段,當開發驅動程序的時候就會使用到它。

3 #pragma once (比較常用)

只要在頭文件的最開始加入這條指令就能夠保證頭文件被編譯一次。這條指令實際上在VC6中就已經有了,但是考慮到兼容性並沒有太多的使用它。

4 #pragma hdrstop

表示預編譯頭文件到此為止,後面的頭文件不進行預編譯。BCB可以預編譯頭文件以加快鏈接的速度,但如果所有頭文件都進行預編譯又可能占太多磁盤空間,所以使用這個選項排除一些頭文件。

有時單元之間有依賴關係,比如單元A依賴單元B,所以單元B要先於單元A編譯。你可以用#pragma startup指定編譯優先級,如果使用了#pragma package(smart_init) ,BCB就會根據優先級的大小先後編譯。

5 #pragma resource “*.dfm”

表示把*.dfm文件中的資源加入工程。*.dfm中包括窗體外觀的定義。

6 #pragma warning( disable : 4507 34; once : 4385; error : 164 )

等價於:

#pragma warning(disable:4507 34) /* 不顯示4507和34號警告信息。如果編譯時總是出現4507號警告和34號警告, 而認為肯定不會有錯誤,可以使用這條指令。*/

#pragma warning(once:4385) // 4385號警告信息僅報告一次

#pragma warning(error:164) // 把164號警告信息作為一個錯誤。

同時這個pragma warning 也支持如下格式:

#pragma warning( push [ ,n ] )

#pragma warning( pop )

這裡n代表一個警告等級(1—4)。

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

#pragma warning( push, n)保存所有警告信息的現有的警告狀態,並且把全局警告等級設定為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)。

7 pragma comment(…)

該指令將一個注釋記錄放入一個對象文件或可執行文件中。

常用的lib關鍵字,可以幫連入一個庫文件。

8 progma pack(n)

指定結構體對齊方式。#pragma pack(n)來設定變量以n字節對齊方式。

n 字節對齊就是說變量存放的起始地址的偏移量有兩種情況:

第一、如果n大於等於該變量所佔用的字節數,那麼偏移量必須滿足默認的對齊方式,

第二、如果n小於該變量的類型所佔用的字節數,那麼偏移量為n的倍數,不用滿足默認的對齊方式。

結構的總大小也有個約束條件,分下面兩種情況:如果n大於所有成員變量類型所佔用的字節數,那麼結構的總大小必須為佔用空間最大的變量佔用的空間數的倍數; 否則必須為n的倍數。

下面舉例說明其用法。

#pragma pack(push) //保存對齊狀態

#pragma pack(4)//設定為4字節對齊

struct test

{

char m1;

double m4;

int m3;

};

#pragma pack(pop)//恢復對齊狀態

為測試該功能,可以使用sizeof()測試結構體的長度!

c語言中預處理命令都有哪些?

我們可以在C源程序中插入傳給編譯程序的各中指令,這些指令被稱為預處理器指令,它們擴充了程序設計的環境。現把常用的預處理命令總結如下:

1. 預處理程序

按照ANSI標準的定義,預處理程序應該處理以下指令:

#if #ifdef #ifndef #else #elif

#endif

#define

#undef

#line

#error

#pragma

#include

顯然,上述所有的12個預處理指令都以符號#開始,,每條預處理指令必須獨佔一行。

2. #define

#define指令定義一個標識符和一個串(也就是字符集),在源程序中發現該標識符時,都用該串替換之。這種標識符稱為宏名字,相應的替換稱為宏代換。一般形式如下:

#define macro-name char-sequence

這種語句不用分號結尾。宏名字和串之間可以有多個空白符,但串開始後只能以新行終止。

例如:我們使用LEFT代表1,用RIGHT代表0,我們使用兩個#define指令:

#define LEFT 1

#define RIGHT 0

每當在源程序中遇到LEFT或RIGHT時,編譯程序都用1或0替換。

定義一個宏名字之後,可以在其他宏定義中使用,例如:

#define ONE 1

#define TWO ONE+ONE

#define THREE ONE+TWO

宏代換就是用相關的串替代標識符。因此,如果希望定義一條標準錯誤信息時,可以如下定義:

#define ERROR_MS “Standard error on input \n”

如果一個串長於一行,可在行尾用反斜線”\”續行,如下:

#define LONG_STRING “This is a very very long \

String that is used as an example”

3. #error

#error指令強制編譯程序停止編譯,它主要用於程序調試。#error指令的一般形式是:

#error error-message

注意,宏串error-message不用雙引號包圍。遇到#error指令時,錯誤信息被顯示,可能同時還顯示編譯程序作者預先定義的其他內容。

4. #include

程序中的#include指令要求編譯程序讀入另一個源文件。被讀入文件的名字必須用雙引號(“”)或一對尖括號()包圍,例如:

#include “stdio.h”

#include stdio.h

都使C編譯程序讀入並編譯頭文件以用於I/O系統庫函數。

包含文件中可以包含其他#include指令,稱為嵌套包含。允許的最大嵌套深度隨編譯器而變。

文件名被雙括號或尖括號包圍決定了對指定文件的搜索方式。文件名被尖括號包圍時,搜索按編譯程序作者的定義進行,一般用於搜索某些專門放置包含文件的特殊目錄。當文件名被雙括號包圍時,搜索按編譯程序實時的規定進行,一般搜索當前目錄。如未發現,再按尖括號包圍時的辦法重新搜索一次。

通常,絕大多數程序員使用尖括號包圍標準的頭文件,雙引號用於包圍與當前程序相關的文件名。

5. 條件編譯指令

若干編譯指令允許程序員有選擇的編譯程序源代碼的不同部分,這種過程稱為條件編譯。

5.1#if、#else、#elif #endif

條件編譯指令中最常用的或許是#if,#else,#elif和#endif。這些指令允許程序員根據常數表達式的結果有條件的包圍部分代碼。

#if的一般形式是:

#if constant-expression

Statement sequence

#endif

如#if後的常數表達式為真,則#if和#endif中間的代碼被編譯,否則忽略該代碼段。#endif標記#if塊的結束。

#else指令的作用與C語言的else相似,#if指令失敗時它可以作為備選指令。例如:

#include stdio.h

#define MAX 100

Int main(void)

{

#if MAX99

printf(“Compiled for array greater than 99.\n”);

#else

printf(“Complied for small array.\n”);

#endif

return 0;

}

注意,#else既是標記#if塊的結束,也標記#else塊的開始。因為每個#if只能寫一個#endif匹配。

#elif指令的意思是“否則,如果”,為多重編譯選擇建立一條if-else-if(如果-否則-如果鏈)。如果#if表達式為真,該代碼塊被編譯,不測試其他#elif表達式。否則,序列中的下一塊被測試,如果成功則編譯之。一般形式如下:

#if expression

Statement sequence

#elif expression1

Statement sequence

#elif expression2

Statement sequence

.

.

.

#elif expression

Statement sequence

#endif

5.2#ifdef和#ifndef

條件編譯的另一個方法是使用編譯指令#ifdef和#ifndef,分別表示“如果已定義”和“如果未定義”。#ifdef的一般形式如下:

#ifdef macro-name

Statement sequence

#endif

如果macro-name原先已經被一個#define語句定義,則編譯其中的代碼塊。

#ifndef的一般形式是:

#ifndef macro-name

Statement sequence

#endif

如果macro-name當前未被#define語句定義,則編譯其中的代碼塊。

我認為,用這種,可以很方便的開啟/關閉整個程序的某項特定功能。

#ifdef和#ifndef都可以使用#else或#elif語句。

#inlucde stdio.h

#define T 10

Int main(void)

{

#ifdef t

Printf(“Hi T\n”);

#else

Printf(“Hi anyone\n”);

#endif

#ifndef M

Printf(“M Not Defined\n”);

#endif

Return 0;

}

6. #undef

#undef指令刪除前面定義的宏名字。也就是說,它“不定義”宏。一般形式為:

#undef macro-name

7. 使用defined

除#ifdef之外,還有另外一種確定是否定義宏名字的方法,即可以將#if指令與defined編譯時操作符一起使用。defined操作符的一般形式如下:

defined macro-name

如果macro-name是當前定義的,則表達式為真,否則為假。

例如,確定宏MY是否定義,可以使用下列兩種預處理命令之一:

#if defined MY

#ifdef MY

也可以在defined之前加上感嘆號”!”來反轉相應的條件。例如,只有在DEBUG未定義的情況下才編譯。

#if !defined DEBUG

Printf(“Final Version!\n”);

#endif

使用defined的一個原因是,它允許由#elif語句確定的宏名字存在。

8. #line

#line指令改變__LINE__和__FILE__的內容。__LINE__和__FILE__都是編譯程序中預定義的標識符。標識符__LINE__的內容是當前被編譯代碼行的行號,__FILE__的內容是當前被編譯源文件的文件名。#line的一般形式是:

#line number “filename”

其中,number是正整數並變成__LINE__的新值;可選的“filename”是合法文件標識符並變成__FILE__的新值。#line主要用於調試和特殊應用。

9. #pragma

#pragma是編譯程序實現時定義的指令,它允許由此向編譯程序傳入各種指令。例如,一個編譯程序可能具有支持跟蹤程序執行的選項,此時可以用#pragma語句選擇該功能。編譯程序忽略其不支持的#pragma選項。#pragma提高C源程序對編譯程序的可移植性。

10. 預處理操作符#和##

有兩個預處理操作符:#和##,它們可以在#define中使用。

操作符#通常稱為字符串化的操作符,它把其後的串變成用雙引號包圍的串。例如:

#include stdio.h

#define mkstr(s) #s

int main(void)

{

Printf(mkstr(I like C));

Return 0;

}

預處理程序把以下的語句:

Printf(mkstr(I like C));

變成

Printf(“I like C”);

操作符##把兩個標記拼在一起,形成一個新標記。例如:

#include stdio.h

#define concat(a,a) a##b

int main(void)

{

Int xy = 10;

Printf(“%d”,concat(x,y));

Return 0;

}

預處理程序把以下語句:

Printf(“%d”,concat(x,y));

變成

Printf(“%d”,xy);

操作符#和##主要作用是允許預處理程序對付某些特殊情況,多數程序中並不需要。

11. 預定義宏

C規範了5個固有的預定義宏,它們是:

__LINE__

__FILE__

__DATE__

__TIME__

__STDC__

__LINE__和__FILE__包含正在編譯的程序的行號和文件名。

__DATE__和內容形如month/day/year(月/日/年)的串,代表源文件翻譯成目標碼的日期。

__TIME__中的串代表源代碼編譯成目標碼的時間,形如hour:minute:second(時:分:秒)

如果__STDC__的內容是十進制常數1,則表示編譯程序的實現符合標準C。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/194375.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-02 14:38
下一篇 2024-12-02 14:38

相關推薦

  • AES加密解密算法的C語言實現

    AES(Advanced Encryption Standard)是一種對稱加密算法,可用於對數據進行加密和解密。在本篇文章中,我們將介紹C語言中如何實現AES算法,並對實現過程進…

    編程 2025-04-29
  • 學習Python對學習C語言有幫助嗎?

    Python和C語言是兩種非常受歡迎的編程語言,在程序開發中都扮演着非常重要的角色。那麼,學習Python對學習C語言有幫助嗎?答案是肯定的。在本文中,我們將從多個角度探討Pyth…

    編程 2025-04-29
  • Python被稱為膠水語言

    Python作為一種跨平台的解釋性高級語言,最大的特點是被稱為”膠水語言”。 一、簡單易學 Python的語法簡單易學,更加人性化,這使得它成為了初學者的入…

    編程 2025-04-29
  • OpenJudge答案1.6的C語言實現

    本文將從多個方面詳細闡述OpenJudge答案1.6在C語言中的實現方法,幫助初學者更好地學習和理解。 一、需求概述 OpenJudge答案1.6的要求是,輸入兩個整數a和b,輸出…

    編程 2025-04-29
  • Python按位運算符和C語言

    本文將從多個方面詳細闡述Python按位運算符和C語言的相關內容,並給出相應的代碼示例。 一、概述 Python是一種動態的、面向對象的編程語言,其按位運算符是用於按位操作的運算符…

    編程 2025-04-29
  • Git config命令用法介紹:用正確的郵箱保障開發工作

    本文將詳細介紹如何使用git config命令配置Git的全局和本地用戶信息,特別是如何正確使用用戶郵箱,保障Git操作的正常進行。 一、git config命令介紹 Git中的每…

    編程 2025-04-29
  • Python命令大全及說明

    Python是一種高級編程語言,由Guido van Rossum於1989年底發明。它具有良好的語法結構和面向對象的編程思想,具有簡潔、易讀、易學的特點,是初學者以及專業開發人員…

    編程 2025-04-29
  • Python SSH 遠程執行命令

    Python SSH 遠程執行命令是指在一個服務器上執行遠程另一個服務器上命令。如果你需要在本地機器上執行命令,或者在遠程機器上執行本地命令,你都可以使用 SSH。在 Python…

    編程 2025-04-29
  • Java和Python哪個功能更好

    對於Java和Python這兩種編程語言,究竟哪一種更好?這個問題並沒有一個簡單的答案。下面我將從多個方面來對Java和Python進行比較,幫助讀者了解它們的優勢和劣勢,以便選擇…

    編程 2025-04-29
  • Python語言由荷蘭人為中心的全能編程開發工程師

    Python語言是一種高級語言,很多編程開發工程師都喜歡使用Python語言進行開發。Python語言的創始人是荷蘭人Guido van Rossum,他在1989年聖誕節期間開始…

    編程 2025-04-28

發表回復

登錄後才能評論