C語言深入講解宏的定義與使用方法
一、C語言中的宏定義
- #define是預(yù)處理器處理的單元實體之一
- #define 定義的宏可以出現(xiàn)在程序的任意位置
- #define 定義之后的代碼都可以使用這個宏
- #define 定義的宏常量可以直接使用
- #define 定義的宏常量本質(zhì)為字面量
下面的宏常量定義正確嗎?

編寫代碼來測試:
#define ERROR -1
#define PATH1 "D:\test\test.c"
#define PATH2 D:\test\test.c
#define PATH3 D:\test\
test.c
int main()
{
int err = ERROR;
char* p1 = PATH1;
char* p2 = PATH2;
char* p3 = PATH3;
}先使用gcc -E Test.c -o Test.i 進(jìn)行預(yù)編譯,預(yù)編譯沒有報錯,結(jié)果如下:
# 1 "Test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "Test.c"
int main()
{
int err = -1;
char* p1 = "D:\test\test.c";
char* p2 = D:\test\test.c;
char* p3 = D:\testtest.c;
}直接進(jìn)行編譯,發(fā)現(xiàn) char* p2 = PATH2; char* p3 = PATH3; 報錯

這說明宏定義是正確的,但是編譯是過不了的,只是
#define PATH2 D:\test\test.c
#define PATH3 D:\test\
不符合語法規(guī)范。
二、宏定義表達(dá)式
- #define 表達(dá)式的使用類似函數(shù)調(diào)用
- #define 表達(dá)式可以比函數(shù)更強大
- #define 表達(dá)式比函數(shù)更容易出錯
強大之處其中之一就是可以求數(shù)組的大小,這是不能編寫函數(shù)辦到的。
下面看一段宏表達(dá)式的代碼:
#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 = 1;
int b = 2;
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("m = %d\n", m);
printf("d = %d\n", d);
return 0;
}
下面為輸出結(jié)果,但是 s2 我們預(yù)期的結(jié)果應(yīng)該是 9,m 的值我們預(yù)期的結(jié)果應(yīng)該是 1,這是怎么回事呢?

下面進(jìn)行預(yù)編譯看看代碼到底是怎么運行的,輸入 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;
}通過上面宏定義的替換,我們很容易知道為什么結(jié)果跟我們想的不一樣。
三、宏表達(dá)式與函數(shù)的對比
- 宏表達(dá)式被預(yù)處理器處理,編譯器不知道宏表達(dá)式的存在
- 宏表達(dá)式用“實參”完全替代形參,不進(jìn)行任何運算
- 宏表達(dá)式?jīng)]有任何的“調(diào)用”開銷
- 宏表達(dá)式中不能出現(xiàn)遞歸定義
所以,下面遞歸定義就是錯誤的:

四、有趣的問題
宏定義的常量或表達(dá)式是否有作用域限制?(沒有)
下面看一個宏作用域分析的代碼:
#include <stdio.h>
void def()
{
#define PI 3.1415926
#define AREA(r) r * r * PI
}
double area(double r)
{
return AREA(r);
}
int main()
{
double r = area(5);
printf("PI = %f\n", PI);
printf("d = 5; a = %f\n", r);
return 0;
}下面為輸出結(jié)果:

作用域的概念是針對 C 語言中的變量和函數(shù),不針對宏。宏表達(dá)式被預(yù)處理器處理,編譯器不知道宏表達(dá)式的存在。
五、強大的內(nèi)置宏
| 宏 | 含義 | 示例 |
| _FILE_ | 被編譯的文件名 | file1.c |
| _LINE_ | 當(dāng)前行號 | 25 |
| _DATE_ | 編譯時的日期 | Jan 31 2021 |
| _TIME_ | 編譯時的時間 | 17:01:01 |
| _STDC_ | 編譯器是否遵循標(biāo)準(zhǔn)C規(guī)范 | 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;
}下面為輸出結(jié)果:

可以看到宏定義是很強大的,可以打印出日期,文件名,行號,不使用宏定義很難實現(xiàn)。
六、小結(jié)
- 預(yù)處理器直接對宏進(jìn)行文本替換
- 宏使用時的參數(shù)不會進(jìn)行求值和運算
- 預(yù)處理器不會對宏定義進(jìn)行語法檢查
- 宏定義時出現(xiàn)的語法錯誤只能被編譯器檢測
- 宏定義的效率高于函數(shù)調(diào)用
- 宏的使用會帶來一定的副作用
到此這篇關(guān)于C語言深入講解宏的定義與使用方法的文章就介紹到這了,更多相關(guān)C語言 宏的定義內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ 多態(tài)性虛函數(shù)和動態(tài)綁定學(xué)習(xí)筆記
這篇文章主要為大家介紹了C++ 多態(tài)性虛函數(shù)和動態(tài)綁定學(xué)習(xí)筆記,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10

