新聞中心
我們?cè)?C 語(yǔ)言中經(jīng)常會(huì)用到宏定義,那么我們今天就對(duì)宏做個(gè)簡(jiǎn)單的介紹。#define 是預(yù)處理期處理的單元實(shí)體之一;它定義的宏可以出現(xiàn)在程序的任意位置;它定義之后的代碼都可以使用這個(gè)宏。
創(chuàng)新互聯(lián)主要業(yè)務(wù)有網(wǎng)站營(yíng)銷(xiāo)策劃、成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、外貿(mào)營(yíng)銷(xiāo)網(wǎng)站建設(shè)、微信公眾號(hào)開(kāi)發(fā)、重慶小程序開(kāi)發(fā)、H5技術(shù)、程序開(kāi)發(fā)等業(yè)務(wù)。一次合作終身朋友,是我們奉行的宗旨;我們不僅僅把客戶當(dāng)客戶,還把客戶視為我們的合作伙伴,在開(kāi)展業(yè)務(wù)的過(guò)程中,公司還積累了豐富的行業(yè)經(jīng)驗(yàn)、全網(wǎng)營(yíng)銷(xiāo)推廣資源和合作伙伴關(guān)系資源,并逐漸建立起規(guī)范的客戶服務(wù)和保障體系。
#define 定義的宏常量可以直接使用,其本質(zhì)為字面量。它與 const 定義的常量的區(qū)別是:const 修飾的常量本質(zhì)是變量,占用內(nèi)存;而字面量是不占用內(nèi)存的。我們來(lái)看看下面這幾個(gè)宏常量定義是否正確
#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; }
我們分析下,前兩個(gè)肯定正確,第三種猜測(cè)是正確的,因?yàn)楹甓x只是簡(jiǎn)單的替換。第四種也是正確的,最后的 \ 我們看成是前面介紹的接續(xù)符。我們來(lái)單步編譯下,看看結(jié)果
我們看到單步編譯的時(shí)候,它沒(méi)出錯(cuò)。就是進(jìn)行簡(jiǎn)單的替換,我們?cè)偌由项^文件,進(jìn)行編譯。結(jié)果如下
我們看到編譯出錯(cuò)了,因?yàn)楹曛皇潜活A(yù)處理期處理,預(yù)處理期不會(huì)去檢查語(yǔ)法,所以會(huì)單步編譯通過(guò)。所以在編譯檢查語(yǔ)法的時(shí)候出錯(cuò)了。我們下來(lái)看個(gè)示例代碼,代碼如下
#include#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; }
我們分析,第14行返回相加和,因而第19行打印 3;第15行返回加和的平方,因而第20行打印 9;第16行返回最小值,因而第21行打印 1;第17行返回的是數(shù)組的個(gè)數(shù),所以第22行打印 4。我們看看編譯結(jié)果
結(jié)果跟我們分析的不太一樣,中間兩個(gè)不一樣。我們來(lái)單步編譯下,看看是什么樣的
我們看到它的 main 函數(shù)是這樣的,因而我們分析的是錯(cuò)的。那么在這塊我們是忽略了宏表達(dá)式和函數(shù)的差異,那么宏表達(dá)式有哪些特性呢?如下:a> 宏表達(dá)式被預(yù)處理器處理,編譯器不知道宏表達(dá)式的存在;b> 宏表達(dá)式用“實(shí)參”完全代替形參,不進(jìn)行任何運(yùn)算;c> 宏表達(dá)式?jīng)]有任何的“調(diào)用”開(kāi)銷(xiāo);d> 宏表達(dá)式中不能出現(xiàn)遞歸定義,如:#define _SUM_(n) ((n > 0) ? (_SUM_(n-1) + n) : 0); int s = _SUM_(5);
那么我們來(lái)思考下:宏定義的常量或表達(dá)式是否有作用域限制?我們來(lái)看看下面的代碼
#includevoid 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; }
那么在 def 函數(shù)里定義的宏能否在 area 函數(shù)里使用呢?也就是說(shuō)宏定義的作用域是否是具有函數(shù)作用域呢,我們來(lái)看看編譯結(jié)果
它并沒(méi)有報(bào)錯(cuò),而是成功運(yùn)行。在這里我們注釋掉頭文件和打印語(yǔ)句,我們來(lái)單步編譯下,看看函數(shù)里是怎樣的?
明顯在 area 函數(shù)里直接展開(kāi)宏,也就是說(shuō)宏定義的常量沒(méi)有作用域的限制。我們?cè)賮?lái)看看 C 語(yǔ)言中強(qiáng)大的內(nèi)置宏
我們利用內(nèi)置宏編寫(xiě)析下面的代碼,代碼如下:
#include#include #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 我們?cè)诘?行定義 MALLOC 為申請(qǐng)堆空間并用指針來(lái)存儲(chǔ)地址,第6行利用之前學(xué)習(xí)的逗號(hào)表達(dá)式來(lái)釋放申請(qǐng)到的指針。第8行則是利用內(nèi)置宏定義 LOG 打印信息,第10-12行分別定義 for 循環(huán)和{ }。我們來(lái)看看編譯后打印的結(jié)果
我們看到內(nèi)置宏是如此的強(qiáng)大,目前在 C 語(yǔ)言中是利用函數(shù)辦不到來(lái)打印文件名和行數(shù)信息的。通過(guò)對(duì)宏定義的學(xué)習(xí),總結(jié)如下:1、預(yù)處理期直接對(duì)宏進(jìn)行文本替換,宏使用時(shí)的參數(shù)不會(huì)進(jìn)行求值和運(yùn)算;2、預(yù)處理期不會(huì)對(duì)宏定義進(jìn)行語(yǔ)法檢查,宏定義出現(xiàn)的緣分錯(cuò)誤只能被編譯器檢測(cè);3、宏定義的效率高于函數(shù)調(diào)用但會(huì)帶來(lái)一定的副作用。后面我們會(huì)繼續(xù)對(duì) C 語(yǔ)言的學(xué)習(xí)。
歡迎大家一起來(lái)學(xué)習(xí) C 語(yǔ)言,可以加我QQ:243343083。
分享名稱(chēng):C之宏定義(十九)
文章地址:http://www.dlmjj.cn/article/pscoge.html