#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
小結:預處理器直接對宏進行文本替換;
宏使用時的參數不會進行求值和運算;
預處理器不會對宏定義進行語法檢查;
宏定義時出現的語法錯誤只能被編譯器檢測;
宏定義的效率高於函數調用;
宏的使用會帶來一定的副作用。