C語言進階:21、宏定義與使用分析

#define是預處理器處理的單元實體之一;
#define定義的宏可以出現在程序的任意位置;

#define定義之後的代碼都可以使用這個宏。

#define定義的宏常量可以直接使用;
#define定義的宏常量本質爲字面量不佔用內存<只讀存儲區>—和const常量(變量,佔內存)的本質區別)。

下面的宏定義正確嗎?

#define error -1                //
#define PATH1 "D:\test.c"
#define PATH2  D:\test.c
#define PATH3  D:\test\        //
test.c

編譯運行:

~/will$ gcc -E test.c -o test.i         //預編譯沒報錯
int main()
{
 int err = -1;
 char* p1 = "D:\test.c";
 char* p2 = D:\test.c;            //error
 char* p3 = D:\testtest.c;        //error
}

~/will$ 
~/will$ gcc test.c
test.c: In function ‘main’:
test.c:13: error: ‘D’ undeclared (first use in this function)
test.c:13: error: (Each undeclared identifier is reported only once
test.c:13: error: for each function it appears in.)
test.c:13: error: expected ‘,’ or ‘;’ before ‘:’ token
test.c:13: error: stray ‘\’ in program
test.c:14: error: expected ‘,’ or ‘;’ before ‘:’ token
test.c:14: error: stray ‘\’ in program

預編譯過程不進行語法語義判斷,表明宏定義是對的,但是編譯後報錯,不合C語言的語法規範。

const常量本質是變量,佔內存;

宏常量不是變量,不佔內存。

        #define表達式的使用類似函數調用;
        #define表達式可以比函數更強大;
        #define表達式比函數更容易出錯。

觀察下面代碼:

#include <stdio.h>

#define _SUM_(a, b) (a) + (b)
#define _MIN_(a, b) ((a) < (b) ? (a) : (b))
#define _DIM_(a) sizeof(a)/sizeof(*a)    //比函數更強大的地方在於可以求一個數組的大小 


int main()
{
    int a = 3;
    int b = 4;
    int c[4] = {0};

    int s1 = _SUM_(a, b);
    int s2 = _SUM_(a, b) * _SUM_(a, b);
    int m = _MIN_(a++, b);
    int d = _DIM_(c);

    printf("s1 = %d\n", s1);
    printf("s2 = %d\n", s2);
    printf("a = %d\n", a);
    printf("m = %d\n", m);
    printf("d = %d\n", d);

    return 0;
}
先單步編譯:
gcc -E test.c -o test.i
得到:
int main()
{
    int a = 1;
    int b = 2;
    int c[4] = {0};

    int s1 = (a) + (b);
    int s2 = (a) + (b) * (a) + (b);
    int m = ((a++) < (b) ? (a++) : (b));
    int d = sizeof(c)/sizeof(*c);

    printf("s1 = %d\n", s1);
    printf("s2 = %d\n", s2);
    printf("m = %d\n", m);
    printf("d = %d\n", d);

    return 0;
}
輸出:
s1 = 3
s2 = 5
m = 2
d = 4
預處理器在處理宏定義時,扮演一個“傳話筒”的作用。
    宏表達式被預處理器處理,編譯器不知道宏表達式的存在;
    宏表達式用“實參”完全替代形參,不進行任何運算
    宏表達式沒有任何的“調用”開銷;

    宏表達式不能出現遞歸定義。

#define _SUM_(n) ((n>0)?(_SUM_(n-1)+n):0)

int s = _SUM_(10);

宏定義的常量或表達式是否有作用域的限制呢?

作用域的概念,針對變量和函數,不針對宏定義。
爲什麼呢?

因爲宏定義是在預編譯階段被處理的,編譯器根本不知道宏定義的存在

強大的內置宏:

  宏			含義					        示例
__FILE__ 		被編譯的文件名				    	file.c
__LINE__		當前行號						25
__DATE___		編譯時的日期					Jan 31 2012
__TIME__		編譯時的時間					17:01:02
__STDC__		編譯時時候遵循標準C規範			        1
注意是雙下劃線。
#include <stdio.h>
#include <malloc.h>
#define MALLOC(type, x) (type*)malloc(sizeof(type)*x)
#define FREE(p) (free(p), p=NULL)
#define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s)
#define FOREACH(i, m) for(i=0; i<m; i++)
#define BEGIN {
#define END   }

int main()

{
    int x = 0;
    int* p = MALLOC(int, 5);    
    LOG("Begin to run main code...");    
    FOREACH(x, 5)

    BEGIN

        p[x] = x;

    END    
    FOREACH(x, 5)
    BEGIN

        printf("%d\n", p[x]);

    END    
    FREE(p);    
    LOG("End"); 
    return 0;

}

運行結果:

~/will$ ./a.out
[May  1 2018] {21-4.c:19} Begin to run main code... 
0
1
2
3
4
[May  1 2018] {21-4.c:33} End 
小結:
預處理器直接對宏進行文本替換
宏使用時的參數不會進行求值和運算;
預處理器不會對宏定義進行語法檢查
宏定義時出現的語法錯誤只能被編譯器檢測;
宏定義的效率高於函數調用;
宏的使用會帶來一定的副作用。


發佈了83 篇原創文章 · 獲贊 12 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章