C語言基礎-07-預處理指令1-宏定義

預處理指令簡介

1.C語言在對源程序進行編譯以前,會先對一些特殊的預處理指令做解釋(好比以前使用的#include文件包含指令),產生一個新的源程序(這個過程稱爲編譯預處理),以後再進行一般的編譯函數

2.爲了區分預處理指令和通常的C語句,全部預處理指令都以符號"#"開頭,而且結尾不用分號spa

3.預處理指令能夠出如今程序的任何位置,它的做用範圍是從它出現的位置到文件尾。習慣上咱們儘量將預處理指令寫在源程序開頭,這種狀況下,它的做用範圍就是整個源程序文件code

4.C語言提供的預處理指令主要有:宏定義文件包含條件編譯orm

這一講先介紹一下宏定義,宏定義能夠分爲2種:不帶參數的宏定義 帶參數的宏定義作用域

1、不帶參數的宏定義

1.通常形式

#define 宏名 字符串字符串

 好比#define ABC 10it

右邊的字符串也能夠省略,好比#define ABCio

2.做用

它的做用是在編譯預處理時,將源程序中全部"宏名"替換成右邊的"字符串",經常使用來定義常量。編譯

接下來寫個程序根據圓的半徑計算周長class

#include <stdio.h>

// 源程序中全部的宏名PI在編譯預處理的時候都會被3.14所代替
#define PI 3.14

// 根據圓的半徑計radius算周長
float girth(float radius) {
    return 2 * PI *radius;
}

int main ()
{
    float g = girth(2);
    
    printf("周長爲:%f", g);
    return 0;
}


在第4行定義了一個叫PI的宏,在編譯預處理以後,第8行中的2 * PI *radius就會變成2 * 3.14 * radius。

輸出結果:

3.使用習慣與注意

1> 宏名通常用大寫字母,以便與變量名區別開來,但用小寫也沒有語法錯誤

2> 對程序中用雙引號擴起來的字符串內的字符,不進行宏的替換操做。好比:

#define R 10
int main ()
{
    char *s = "Radio";
    return 0;
}

在第1行定義了一個叫R的宏,可是第4行中"Radio"裏面的'R'並不會被替換成10

3> 在編譯預處理用字符串替換宏名時,不做語法檢查,只是簡單的字符串替換。只有在編譯的時候纔對已經展開宏名的源程序進行語法檢查

#define I 100
int main ()
{
    int i[3] = I;
    return 0;
}

在作編譯預處理的時候,無論語法對不對,第4行的I都會被替換爲100。不過在編譯的時候就會報第4行的錯。

4> 宏名的有效範圍是從定義位置到文件結束。若是須要終止宏定義的做用域,能夠用#undef命令

#define PI 3.14
/*
.
.
.
.
*/
#undef PI

PI這個宏在第1行到第8行之間是有效的,第8行後就無效了

5> 定義一個宏時能夠引用已經定義的宏名

#define R  3.0
#define PI 3.14
#define L  2*PI*R
#define S  PI*R*R

2、帶參數的宏定義

1.通常形式

#define 宏名(參數列表) 字符串

2.做用

在編譯預處理時,將源程序中全部宏名替換成字符串,而且將 字符串中的參數 用 宏名右邊參數列表 中的參數替換

#include <stdio.h>

#define average(a, b) (a+b)/2

int main ()
{
    int a = average(10, 4);
    
    printf("平均值:%d", a);
    return 0;
}

第3行中定義了一個帶有2個參數的宏average,第7行其實會被替換成:int a = (10 + 4)/2;,輸出結果爲:。是否是感受這個宏有點像函數呢?

3.使用注意

1> 宏名和參數列表之間不能有空格,不然空格後面的全部字符串都做爲替換的字符串

#define average (a, b) (a+b)/2

int main ()
{
    int a = average(10, 4);
    return 0;
}


注意第1行的宏定義,宏名average跟(a, b)之間是有空格的,因而,第5行就變成了這樣:

int a = (a, b) (a+b)/2(10, 4);

這個確定是編譯不經過的

帶參數的宏在展開時,只做簡單的字符和參數的替換,不進行任何計算操做。因此在定義宏時,通常用一個小括號括住字符串的參數。

下面定義一個宏D(a),做用是返回a的2倍數值:

  • 若是定義宏的時候不用小括號括住參數

#include <stdio.h>

#define D(a) 2*a

int main ()
{
    int b = D(3+4);
    
    printf("%d", b);
    return 0;
}

7行將被替換成int b = 2*3+4;,輸出結果:

  • 若是定義宏的時候小括號括住參數,把上面的第3行改爲:

#define D(a) 2*(a)

注意右邊的a是有括號的,第7行將被替換成int b = 2*(3+4);,輸出結果:

3> 計算結果最好也用括號括起來

下面定義一個宏P(a),做用是返回a的平方:

  • 若是不用小括號括住計算結果

#include <stdio.h>

#define Pow(a) (a) * (a)

int main(int argc, const char * argv[]) {
    int b = Pow(10) / Pow(2);
    
    printf("%d", b);
    return 0;
}

注意第3行,沒有用小括號擴住計算結果,只是括住了參數而已。第6行代碼被替換爲:

int b = (10) * (10) / (2) * (2);

簡化以後:int b = 10 * (10 / 2) * 2;,最後變量b爲:

  • 若是小括號括住計算結果

將上面的第3行代碼改成:

#define Pow(a) ( (a) * (a) )

那麼第6行被替換爲:

int b = ( (10) * (10) ) / ( (2) * (2) );

簡化以後:int b = (10 * 10) / (2 * 2);,最後輸出結果:。這個纔是咱們想要的結果。

也就意味着前面的#define average(a, b) (a+b)/2應該寫成#define average(a, b) (((a)+(b))/2)

 

5.與函數的區別

從整個使用過程能夠發現,帶參數的宏定義,在源程序中出現的形式與函數很像。可是二者是有本質區別的:

1> 宏定義不涉及存儲空間的分配、參數類型匹配、參數傳遞、返回值問題

2> 函數調用在程序運行時執行,而宏替換隻在編譯預處理階段進行。因此帶參數的宏比函數具備更高的執行效率

相關文章
相關標籤/搜索