詳解C語(yǔ)言#define預(yù)處理宏定義
#define介紹:
C語(yǔ)言里可以用#define定義一個(gè)標(biāo)識(shí)符來(lái)表示一個(gè)常量。特點(diǎn)是:定義的標(biāo)識(shí)符不占內(nèi)存,只是一個(gè)臨時(shí)的符號(hào),預(yù)編譯后這個(gè)符號(hào)就不存在了,也不做類型定義。預(yù)編譯又叫預(yù)處理。預(yù)編譯就是編譯前的處理。這個(gè)操作是在正式編譯之前由系統(tǒng)自動(dòng)完成的。
#define又稱宏定義,標(biāo)識(shí)符為所定義的宏名,簡(jiǎn)稱宏。標(biāo)識(shí)符的命名規(guī)則和變量的命名規(guī)則是一樣的。#define的功能是將標(biāo)識(shí)符定義為其后的常量,一經(jīng)定義,程序中就可以直接用標(biāo)識(shí)符來(lái)表示這個(gè)常量,也就是文本替換。變量名表示的是一個(gè)變量,但宏名表示的是一個(gè)常量,可以給變量賦值,但絕不能給常量賦值。
宏定義最大的好處是方便程序的修改。使用宏定義可以用宏代替一個(gè)在程序中經(jīng)常使用的常量。這樣,當(dāng)需要改變這個(gè)常量的值時(shí),就不需要對(duì)整個(gè)程序一個(gè)一個(gè)進(jìn)行修改,只需修改宏定義中的常量就行了。且當(dāng)常量比較長(zhǎng)時(shí),使用宏就可以用較短的有意義的標(biāo)識(shí)符來(lái)代替它,這樣編程的時(shí)候就會(huì)更方便,不容易出錯(cuò)。因此,宏定義的優(yōu)點(diǎn)就是方便和易于維護(hù)。
#define宏定義無(wú)參的一般形式為:#define 標(biāo)識(shí)符 常量
注意最后沒(méi)有分號(hào),因?yàn)楹瓴皇钦Z(yǔ)句,結(jié)尾不用加分號(hào),否則會(huì)被替換進(jìn)進(jìn)程中。還有一點(diǎn)就是宏名最好用大寫字母加下劃線組成,以此來(lái)區(qū)分變量名。
來(lái)看一個(gè)#define宏定義無(wú)參的例子:
#include<stdio.h>
#define PI 3.1415926//標(biāo)識(shí)符或宏名叫PI 常量是個(gè)浮點(diǎn)型 作用是圓周率
#define R 2//標(biāo)識(shí)符或宏名叫R 常量是個(gè)整型 作用是圓的半徑
#define PRINT "半經(jīng)為2的圓 面積=%lf\n"http://標(biāo)識(shí)符或宏名叫PRINT 常量是個(gè)字符串 作用是代替了printf()函數(shù)的第一個(gè)參數(shù)
int main()
{
printf(PRINT,PI*R*R);//在這里PRINT被替換成"半經(jīng)為2的圓 面積=%lf" PI被替換成3.1415926 R被替換成2
printf("半經(jīng)為2的圓 面積=%lf\n",3.1415926*2*2);//這句是上面一句代碼替換后的代碼
return 0;
}
#define宏定義有參的一般形式為:#define 標(biāo)識(shí)符(參數(shù)表) 表達(dá)式
帶參數(shù)的宏定義,宏名中不能有空格,宏名與形參表之間也不能有空格,而形參表中形參之間可以有空格。
來(lái)看一個(gè)#define宏定義有參的例子:
#include<stdio.h>
#define SQUARE(x) x*x//標(biāo)識(shí)符或宏名叫SQUARE 表達(dá)式是x*x 作用是算x的平方
int main()
{
printf("%d %d\n",SQUARE(3),SQUARE(4));//SQUARE(3)被替換成3*3 SQUARE(4)被替換成4*4
printf("%d %d\n",3*3,4*4);//這句是上面一句代碼替換后的代碼
return 0;
}
我門來(lái)稍微改動(dòng)下代碼:
#include<stdio.h>
#define SQUARE(x) x*x//標(biāo)識(shí)符或宏名叫SQUARE 表達(dá)式是x*x 作用是算x的平方
int main()
{
printf("%d %d\n",SQUARE(2+1),SQUARE(3+1));
return 0;
}
這里只是把傳的參數(shù)3被改成了2+1,4被改成了3+1,可能有些朋友會(huì)說(shuō)2+1=3,3+1=4,答案不就和剛才一樣嘛。其實(shí)不是,因?yàn)?define宏定義只是簡(jiǎn)單的文本替換,那應(yīng)該被替換成什么呢。SQUARE(2+1)和SQUARE(3+1)分別替換成2+1*2+1和3+1*3+1, 那么最終答案自然是5和7了。那么如何杜絕這個(gè)問(wèn)題呢?
很簡(jiǎn)單,只要在傳參時(shí)多加一層小括號(hào):
#include<stdio.h>
#define SQUARE(x) x*x//標(biāo)識(shí)符或宏名叫SQUARE 表達(dá)式是x*x 作用是算x的平方
int main()
{
printf("%d %d\n",SQUARE((2+1)),SQUARE((3+1)));//SQUARE((2+1))被替換成(2+1)*(2+1) SQUARE((3+1))被替換成(3+1)*(3+1)
printf("%d %d\n",(2+1)*(2+1),(3+1)*(3+1));//這句是上面一句代碼替換后的代碼
return 0;
}
如果覺得這樣太繁雜,麻煩了,那么直接在宏定義的表達(dá)式那里的每個(gè)參數(shù)都加上小括號(hào):
#include<stdio.h>
#define SQUARE(x) (x)*(x)//標(biāo)識(shí)符或宏名叫SQUARE 表達(dá)式是x*x 作用是算x的平方
int main()
{
printf("%d %d\n",SQUARE(2+1),SQUARE(3+1));//SQUARE((2+1))被替換成(2+1)*(2+1) SQUARE((3+1))被替換成(3+1)*(3+1)
printf("%d %d\n",(2+1)*(2+1),(3+1)*(3+1));//這句是上面一句代碼替換后的代碼
return 0;
}
我們又來(lái)稍微改動(dòng)下代碼:
#include<stdio.h>
#define SQUARE(x) (x)*(x)//標(biāo)識(shí)符或宏名叫SQUARE 表達(dá)式是x*x 作用是算x的平方
int main()
{
printf("%d %d\n",9/SQUARE(3),16/SQUARE(4));
return 0;
}
這里在傳參數(shù)之前加了個(gè)除法,那么3*3后是9,再被9除,等于1,4*4后是16,再被16除,等于1,那么預(yù)想的最終答案就是1和1了,其實(shí)也不是。再來(lái)一次文本替換,9/SQUARE(3)和16/SQUARE(4)分別替換成9/(3)*(3)和16/(4)*(4), 那么最終答案自然是9和16了。那么又如何杜絕這個(gè)問(wèn)題呢?
也很簡(jiǎn)單,只要在傳參時(shí)多加一層小括號(hào):
#include<stdio.h>
#define SQUARE(x) (x)*(x)//標(biāo)識(shí)符或宏名叫SQUARE 表達(dá)式是x*x 作用是算x的平方
int main()
{
printf("%d %d\n",9/(SQUARE(3)),16/(SQUARE(4)));//9/(SQUARE(3))和16/(SQUARE(4))分別替換成9/((3)*(3))和16/((4)*(4))
printf("%d %d\n",9/((3)*(3)),16/((4)*(4)));//這句是上面一句代碼替換后的代碼
return 0;
}
如果依然覺得這樣太繁雜,麻煩了,那么直接在宏定義的表達(dá)式那里的整個(gè)表達(dá)式都加上小括號(hào):
#include<stdio.h>
#define SQUARE(x) ((x)*(x))//標(biāo)識(shí)符或宏名叫SQUARE 表達(dá)式是x*x 作用是算x的平方
int main()
{
printf("%d %d\n",9/SQUARE(3),16/SQUARE(4));//9/(SQUARE(3))和16/(SQUARE(4))分別替換成9/((3)*(3))和16/((4)*(4))
printf("%d %d\n",9/((3)*(3)),16/((4)*(4)));//這句是上面一句代碼替換后的代碼
return 0;
}
表達(dá)式也可以寫多個(gè)語(yǔ)句:
#include<stdio.h>
#define AB(a,b) a=i+5,b=j+3
int main()
{
int i=3,j=5,m=0,n=0;
AB(m,n);//AB(m,n)被替換成m=i+5,n=j+3
printf("%d %d\n",m,n);
return 0;
}
#運(yùn)算符:
#運(yùn)算符的作用就是將#后邊的宏參數(shù)進(jìn)行字符串的操作,也就是將#后邊的參數(shù)兩邊加上一對(duì)雙引號(hào)使其成為字符串。例如param是一個(gè)宏的形參,則替換文本中的#param被系統(tǒng)轉(zhuǎn)化為"param",這個(gè)轉(zhuǎn)換過(guò)程即為字符串化。如下代碼:
#include<stdio.h>
#define TEST(param) #param//標(biāo)識(shí)符或宏名叫TEST 表達(dá)式是#param 作用是把param參數(shù)轉(zhuǎn)換為字符串
int main()
{
printf("%s\n",TEST(換行前\n第一次換行\(zhòng)n第二次換行));//TEST(換行前\n第一次換行\(zhòng)n第二次換行)被替換成"換行前\n第一次換行\(zhòng)n第二次換行"
printf("換行前\n第一次換行\(zhòng)n第二次換行\(zhòng)n");//這句是上面一句代碼替換后的代碼
return 0;
}
##運(yùn)算符:
##運(yùn)算符也可以用在替換文本中,它的作用起到粘合的作用,即將兩個(gè)宏參數(shù)連接為一個(gè)數(shù)。如下代碼:
#include<stdio.h>
#define TEST(param1,param2) (param1##param2)//標(biāo)識(shí)符或宏名叫TEST 表達(dá)式是(param1##param2) 作用是把param1參數(shù)和param2參數(shù)和連接為一個(gè)數(shù)
int main()
{
printf("%d\n",TEST(12,34));//TEST(12,34)被替換成(1234)
printf("%d\n",(1234));//這句是上面一句代碼替換后的代碼
return 0;
}
可變宏...和__VA_ARGS__:
可變宏...和__VA_ARGS__的作用主要是為了方便管理軟件中的打印信息。在寫代碼或DEBUG時(shí)通常需要將一些重要參數(shù)打印出來(lái),但在軟件發(fā)行的時(shí)候不希望有這些打印,這時(shí)就用到可變參數(shù)宏了。如下代碼:
#include<stdio.h>
#define PRINT(...) printf(__VA_ARGS__)//標(biāo)識(shí)符或宏名叫PRINT 表達(dá)式是printf(__VA_ARGS__) __VA_ARGS__被用在替換文本中,來(lái)表示省略號(hào)...代表了什么
int main()
{
PRINT("hello\n");//PRINT("hello\n")被替換成printf("hello\n")
printf("hello\n");//這句是上面一句代碼替換后的代碼
return 0;
}
在宏定義中,形參列表的最后一個(gè)參數(shù)為省略號(hào)...,而__VA_ARGS__被用在替換文本中,來(lái)表示省略號(hào)...代表了什么。
開發(fā)項(xiàng)目中常用的宏定義:
防止頭文件被重復(fù)包含:
#ifndef COMDEF_H #define COMDEF_H //頭文件的內(nèi)容 #endif
得到一個(gè)制定地址上的一個(gè)字節(jié)或字:
#define MEM_B(X) (*((byte*)(x))) #define MEM_W(X) (*((word*)(x)))
求最大值與最小值:
#define MAX(x,y) ((x)>(y)?(x):(y)) #define MIN(x,y) ((x)<(y)?(x):(y))
得到一個(gè)結(jié)構(gòu)體中field所占用的字節(jié)數(shù):
#define FSIZ(type,field) sizeof(((type*)0)->field)
得到一個(gè)field在結(jié)構(gòu)體中的偏移量:
#define FPOS(type,field)\((dword)&(((type*)0)->field)
按照LSB格式把兩個(gè)字節(jié)轉(zhuǎn)化為一個(gè)word:
#define FLIPW(ray) (((word)(ray)[0]*256)+(ray)[1])
按照LSB格式將一個(gè)WORD轉(zhuǎn)化為兩個(gè)字節(jié):
#define FLOPW(ray,val) (ray)[0]=((val)/256);(ray)[1]=((val)&0xFF)
得到一個(gè)變量的地址:
#define B_PTR(var) ((byte*)(void*)&(var)) #define W_PTR(var) ((word*)(void*)&(var))
得到一個(gè)字的高位與低位字節(jié):
#define WORD_LO(xxx) ((byte)((word)(xxx)&255)) #define WORD_HI(xxx) ((byte)((word)(xxx)>>8))
用宏得到一個(gè)數(shù)組所含的元素個(gè)數(shù):
#define ARR_SIZE(a) (sizeof(a)/sizeof((a)[0]))
到此這篇關(guān)于詳解C語(yǔ)言#define預(yù)處理宏定義 的文章就介紹到這了,更多相關(guān)C語(yǔ)言#define預(yù)處理宏定義 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Microsoft Visual C++ 安裝失敗 0x80070666的問(wèn)題解
本文主要介紹了Microsoft Visual C++ 安裝失敗 0x80070666的問(wèn)題解決,錯(cuò)誤可能由已安裝其他VisualC++版本、VisualC++安裝異常、Windows更新計(jì)劃安裝同一VisualC++包等原因引起,下面就來(lái)介紹一下解決方案,感興趣的可以了解一下2025-03-03
C語(yǔ)言單鏈表實(shí)現(xiàn)多項(xiàng)式相加
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言單鏈表實(shí)現(xiàn)多項(xiàng)式相加,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
C語(yǔ)言實(shí)現(xiàn)支持動(dòng)態(tài)拓展和銷毀的線程池
這篇文章主要為大家介紹了C語(yǔ)言實(shí)現(xiàn)支持動(dòng)態(tài)拓展和銷毀的線程池,感興趣的小伙伴們可以參考一下2016-01-01
C++分析如何用虛析構(gòu)與純虛析構(gòu)處理內(nèi)存泄漏
虛析構(gòu)和純虛析構(gòu)共性:可以解決父類指針釋放子類對(duì)象,都需要有具體的函數(shù)實(shí)現(xiàn);虛析構(gòu)和純虛析構(gòu)區(qū)別:如果是純虛析構(gòu),該類屬于抽象類,無(wú)法實(shí)例化對(duì)象2022-08-08
Qt使用QCamera實(shí)現(xiàn)切換相機(jī),分辨率和圖像捕獲功能
這篇文章主要為大家介紹了如何利用Qt中的相機(jī)類QCamera,取景器類QCameraViewfinder,圖像捕獲類QCameraImageCapture實(shí)現(xiàn)切換相機(jī)、分辨率和圖像捕獲功能,需要的可以了解一下2023-04-04
簡(jiǎn)要對(duì)比C語(yǔ)言中的dup()函數(shù)和dup2()函數(shù)
這篇文章主要介紹了簡(jiǎn)要對(duì)比C語(yǔ)言中的dup()函數(shù)和dup2()函數(shù),是C語(yǔ)言入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-08-08

