當前位置:才華齋>計算機>C語言>

C語言預處理的相關知識

C語言 閱讀(1.35W)

導語:在C語言編譯的時候,會經歷以下幾個步驟:預處理,編譯,彙編,連結,然後生成可執行檔案。整個過程是一連串動作完成的。而預處理階段呢,也是在最先執行的一個步驟。相對來說,也是比較重要的一個步驟。那麼C語言預處理的相關知識呢?一起來學習下吧:

C語言預處理的相關知識

概念: 以“#”號開頭的預處理指令如包含#include,巨集定義制定#define等,在源程式中這些指令都放在函式之外,而且一般放在原始檔的前面 ,所謂預處理其實就是在編譯的第一遍掃描之前的所作的工作,預處理是c語言的一個重要的功能,它由預處理程式單獨完成,當對一個原始檔進行編譯時,系統自動引用預處理程式,預處理在 原始碼編譯之前對其進行的一些文字性質的操作,對源程式編譯之前做一些處理,生成擴充套件的C源程式

 預處理階段做了任務:

1:將標頭檔案中的內容(原始檔之外的檔案)插入到原始檔中

2:進行了巨集替換的過程,定義和替換了由#define指令定義的符號

3:刪除掉註釋的過程,註釋是不會帶入到編譯階段

4:條件編譯

  預處理指令:

gcc -E bin/helloworld.i src/helloworld.c

預處理生成的是.i的文字檔案,這個文字檔案是可以直接通過cat命令進行文字檔案檢視的

 巨集定義

在C語言中允許用一個識別符號來表示一個字串;稱為巨集,在預處理時,對程式的巨集進行替換,其中巨集定義是由源程式中的#define來完成 ,而巨集的替換,主要是由預處理程式完成的

#define PI 3.1415

  巨集定義的規則:

#表示一條預處理的指令,以#開頭的均是預處理指令

#define是巨集定義的指令,識別符號是所定義的巨集名

巨集名一般都是大寫的字母表示,以便和變數名區別

巨集定義其實並不是C語言的'語句,所以後面是不用去加;號

巨集體可以是常數,表示式,格式化字串等,為表示式的時候應該用括號闊起來

巨集替換不分配記憶體空間,也不做正確性的檢查

巨集的範圍是從定義後到本原始檔的結束,但是可以通過#undef來進行提前取消

巨集定義分為有參巨集定義和無參巨集定義:

無參巨集定義:

語法:

#define 識別符號(巨集名)[字串]

巨集體可預設:

#define YES 1

#define NO 0

#define OUT printf("Hello world")

#define WIDTH 80

#define LENGTH (WIDTH+40)

巨集的移除語法

#undef 巨集名

功能:刪除前面定義的巨集

事例:

#undef PI

#undef OUT

#undef YES

#undef NO

帶參巨集定義:

帶參巨集定義的語法結構

#define 巨集名(形參列表) 字串(巨集體)

帶引數巨集定義呼叫:

巨集名(實參表);

C語言中允許巨集帶有引數,在巨集定義的引數中稱為形式引數,形式引數不分配記憶體單元,沒有型別定義;

#define S(a,b) a*b;

area = S(3,2);

巨集展開 area = 3 * 2;

注意事項:

帶引數巨集定義中,巨集名和形式引數列表之間不能有空格出現。如

#define MAX (a,b) (a>b)?a:b

此時MAX為無參的巨集定義,巨集體為(a,b) (a>b)?a:b

#define MAX(a,b) (a>b)?a:b

巨集定義中,形參是一個識別符號,而巨集呼叫的引數可以是一個表示式

巨集體內的形參通常要括號闊起來

#define POWER(x) ((x)*(x))

條件編譯

條件編譯的概念

1:一般情況下,源程式中所有的行都進行編譯,但是有時希望對其中一部分內容滿足一定條件下才進行編譯,也就是對一部分內容指定編譯條件,這就是條件編譯

條件編譯的優點

條件編譯可以指定程式碼的一部分是被正常編譯還是被完全忽略

條件編譯有利於提升程式的可移植性,增強程式 的靈活性

條件編譯的相關語法

條件編譯語法一:

#ifdef 識別符號(巨集名) //或者#if define(識別符號)

程式段1

#else

程式段2

#endif

例項程式碼:防止多重包含的問題產生

#define HELLO "helloworld"

#ifdef HELLO

#define HI "welcome"

#endif

條件編譯語法二:

#ifndef 識別符號(巨集名) //或#if !define(識別符號)

程式段1

#else

程式段2

#endif

例項:

#ifndef __HELLO_H__

#define __HELLO_H__

void out();

#else

//程式段2

#endif

條件編譯語法三:

#if(常量表達式)

程式段1

#elif(常量表達式2)

程式段2

#else

程式段3

#endif

例項程式碼:

#define C1 0

#define C2 0

#define C3 1

#if(C1)

#include "c1.h"

#elif(C2)

#include "c2.h"

#elif(C3)

#include "c3.h"

#else

#include "c.h"

#endif

 檔案包含

檔案包含的概念

檔案包含是C預處理程式的另一個重要的功能,被包含的檔名字必須使用雙引號”“(自定義標頭檔案),或者<>(標準庫檔案)括起來,

檔案包含的語法:

#include <檔名>

或者

#include "檔名"

檔案包含的功能:

一個原始檔可以將另外一個原始檔的內容包含進來,從而把指定的檔案和當前的原始檔連成一個原始檔

檔案包含的處理過程:

在預處理的時候,用被包含檔案的內容取代該檔案包含指令,再對包含後的檔案作一個原始檔編譯

檔案包含的搜尋方式

#include<檔名>

若指定檔案目錄(如include)則會從指定目錄中去進行查詢,否則就會按照標準的方式進行查詢

如:(gcc -o bin/hello -Iinclude src/hello)

標準方式:從系統標準檔案所在的目錄中去尋找要包含的檔案

linux下:/usr/include或者/usr/lib中主要存放的是標準庫檔案

#include "檔名"

先從存放C原始檔的目錄中查詢,然後從指定的目錄中去查詢,最後再從C語言的標準庫檔案中去查詢

重要:檔案的多重包含問題

概念:同一個檔案被包含了多次

結果:多重包含可能會出現重複定義的編譯錯誤

解決方式:使用條件編譯(只能是一個原始檔中去解決)來防止多重包含,凡是在標頭檔案前後,用條件編譯去編譯

如標準標頭檔案的寫法:

#ifndef __HEADER_NAME_H__

#define __HEADER_NAME_H__

#include "headername.h"

//其他的程式碼

#endif

如果在多個原始檔中進行多重包含的話,使用多重包含的話是解決不了的。需要檢查。

建議注意:

在標頭檔案中儘量不要去定義一些全域性變數,可以在原始檔中去定義,用extern去修飾,將變數的作用於釋放帶整個程式

預處理操作符和預定義巨集

預處理操作符號:#和##

C語言中有兩個預處理操作符號#和##,它可以在#define中使用

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

如:#define PRINT(FORMAT,VALUE) printf("the value of" #value "is" FORMAT "",VALUE)

PRINT("%d",x+3);

連線操作符號##可以把兩個獨立的字串連結成一個字串

如:

#define ADD_TO_SUM(sum_number,value) sum##sum_number +=value

ADD_TO_SUM(5,25);

預定義巨集和其他指令:

__FILE__ 進行編譯的原始檔名稱

__LINE__ 檔案當前的行號

__DATE__檔案被編譯的日期

__TIME__檔案被編譯的時間

__fun__當前所在的函式名稱

其他預處理

#error 自定義輸出的錯誤,是不能連結生成可執行檔案的

#line 設定當前的檔案從哪一行開始計算

#line 100 "hello.c"

#pragma 位元組對齊預處理指令

#pragma message("helloworld");----->輸出提示相關資訊

以上是個人在學習過程中所做的一些總結性東西,如有不對的地方,希望可以及時指出,歡迎繼續訪問。