C/C++中宏定義(#define)
#define是C語(yǔ)言中提供的宏定義命令,其主要目的是為程序員在編程時(shí)提供一定的方便,并能在一定程度上提高程序的運(yùn)行效率,但學(xué)生在學(xué)習(xí)時(shí)往往不能 理解該命令的本質(zhì),總是在此處產(chǎn)生一些困惑,在編程時(shí)誤用該命令,使得程序的運(yùn)行與預(yù)期的目的不一致,或者在讀別人寫的程序時(shí),把運(yùn)行結(jié)果理解錯(cuò)誤,這對(duì) C語(yǔ)言的學(xué)習(xí)很不利。
宏的定義在程序中是非常有用的,但是使用不當(dāng),就會(huì)給自身造成很大的困擾。通常這種困擾為:宏使用在計(jì)算方面。
本例子主要是在宏的計(jì)算方面,很多時(shí)候,大家都知道定義一個(gè)計(jì)算的宏,對(duì)于編譯和編程是多么的有用?,F(xiàn)在定義有以下一個(gè)計(jì)算 “乘法” 的宏。
#include <stdio.h> #define MUL(a) ((a)*(a)*(a)) int main(int argc,char *argv[]) { int i = 10; int sum = MUL(i); printf("MUL(%d) = %d\n",i,sum); return 0; } </stdio.h>
上面程序的這種做法對(duì)于非負(fù)數(shù)而言那就是沒有問(wèn)題的,比如,程序中的 變量 i=10,這個(gè)時(shí)候,調(diào)用宏得到的數(shù)據(jù)如下:
但是如何變量的數(shù)值是自加或者自減的操作的話,結(jié)果就不一樣了。
假如我們將上面的程序變?yōu)橄旅孢@樣的
#include <stdio.h> #define MUL(a) ((a)*(a)*(a)) int main(int argc,char *argv[]) { int i = 10; int sum = MUL(++i); printf("MUL(%d) = %d\n",i,sum); return 0; } </stdio.h>
得到的結(jié)果并不是 11 * 11 *11 = 1331這個(gè)數(shù)據(jù),而是 1872,這時(shí)候有人會(huì)問(wèn)為什么?
得到宏的朋友或者了解過(guò)宏在計(jì)算方面的朋友就會(huì)知道,這除了是宏的問(wèn)題,還是本身程序員編寫這段代碼的問(wèn)題。當(dāng)使用了 ++i 和 i++ 的時(shí)候,
要特別注意在宏中是全部使用 ++i或者i++的,變成的格式如下
MUL(i++) ((i++)*(i++)*(i++)) MUL(++i) ((++i)*(++i)*(++i))
上述的做法顯然不是我們想要的計(jì)算結(jié)果,可能在我們程序中看到的是MUL(++i) 或者 MUL(i++),認(rèn)為實(shí)際上是如下情況:
//當(dāng)i的初始化數(shù)值為10的時(shí)候,進(jìn)行i++的 MUL(i++)宏計(jì)算,即是:int i = 10;
//MUL(i ++)的數(shù)值計(jì)算結(jié)果相比是 10 * 11 * 12的,這是沒有問(wèn)題的,但是 i的值呢??是11嗎??顯然不是。 MUL(i++) = 10 * 11 *12;i = ??;
i的數(shù)值如下圖所示
誠(chéng)然,i的數(shù)值變成了 13,這是為什么呢??
那就是因?yàn)檫@個(gè)MUL(a)這個(gè)宏和程序員的 “自加自減” 操作所造成的。這里先普及一下 C/C++語(yǔ)言的 “自加自減” 操作:
//自加自減的操作
i++ 和 ++i ----> 這里的操作屬于++后操作,可以替換成 i = i+1 的結(jié)果。
但是,當(dāng)它賦值給一個(gè)變量的時(shí)候,表示的內(nèi)容和含義就有不同: (假設(shè)i = 10)
1. sum1 = i++;
2. sum2 = ++i;
1中的sum1的數(shù)值就是 10, i為 11
2中的sum2的數(shù)值就是 11, i為 11
這是因?yàn)椋?/p>
i++ 操作是 先賦值給 sum1后,自己在執(zhí)行 i = i+1的操作
++i 操作是 先進(jìn)行 i = i+ 1的操作,然后再賦值給sum2
這樣得到的結(jié)果當(dāng)然不同了,但是i最終的結(jié)果是要加1的,只不過(guò)是賦值給變量的時(shí)候會(huì)有不同
通過(guò)對(duì)自加自減的操作進(jìn)行說(shuō)明,不知道大家是否明白為什么了嗎??
當(dāng) i = 10的時(shí)候,MUL(i++)就是為 (i++)*(i++)*(i++)的計(jì)算結(jié)果,考慮到C/C++的運(yùn)算符結(jié)合性,
先計(jì)算第一個(gè) i++,這是一個(gè)先計(jì)算后賦值的自加方式,那么這是后第一個(gè) (i++)的數(shù)值待定為 10 ,那么第
二個(gè)的i是因?yàn)榈谝粋€(gè)數(shù)據(jù)的 (i++)起了作用而變化的,這時(shí)候第二個(gè)(i++)的數(shù)值為11,然后加1,這時(shí)候 根
據(jù)結(jié)合性,先計(jì)算前面兩個(gè)數(shù)據(jù),就是(i++) * (i++)的數(shù)值了,即為:10 * 11了,這時(shí)候的i數(shù)值是 12;
然后計(jì)算第三個(gè) i++的數(shù)值,這時(shí)候第三個(gè)i++中的i數(shù)值為 12,計(jì)算后再加1,也就是說(shuō),10 * 11 * 12之后,
i= 12 的數(shù)值在進(jìn)行i++變?yōu)?13了。所以 MUL(i++) = 10 * 11 * 12 = 1320。
另外,在進(jìn)行++i的操作和上述的情況差不多,只不過(guò)是先做自加的運(yùn)算,在進(jìn)行賦值。
當(dāng) i = 10的時(shí)候,MUL(++i)實(shí)際上也為 (++i)*(++i)*(++i)的方式,這時(shí)候先計(jì)算第一個(gè) (++i),這是一
個(gè)先計(jì)算后賦值的結(jié)合方式,那么 i = i+1 = 11;這時(shí)候準(zhǔn)備計(jì)算第二個(gè)(++i)的時(shí)候,因?yàn)樾枰扔?jì)算后賦值,
所以 第二個(gè) ++i 之后的數(shù)值為12,但是因?yàn)閕屬于同一個(gè)變量和屬性,那么第一個(gè)i也會(huì)變成 12了,這時(shí)候結(jié)合性
考慮應(yīng)該是計(jì)算前兩個(gè)(++i)的結(jié)果,再與第三個(gè)(++i)計(jì)算,即(++i)*(++i) = 12 * 12;然后,我們計(jì)算第三個(gè)
(++i)的數(shù)值,由于前面第二個(gè)++i的i值,所以第三個(gè)++i即為 13,此時(shí),12 * 12 * 13。
有人可能顧慮,為什么最后不是13 * 13 * 13的呢?那不是最后都是13嗎?? ------》其實(shí)這種想法是錯(cuò)誤的,
這必須先理解運(yùn)算符的結(jié)合性。我們知道,當(dāng)計(jì)算中遇到了括號(hào)的時(shí)候,我們先計(jì)算括號(hào)的內(nèi)容,這是我們?cè)跀?shù)學(xué)中的慣性思維。但是對(duì)于計(jì)算機(jī)而言,計(jì)算機(jī)必須 有計(jì)算的優(yōu)先級(jí),也就是運(yùn)算符的優(yōu)先級(jí)問(wèn)題。首先我們計(jì)算前面兩個(gè)括號(hào)的內(nèi)容,以為兩個(gè)括號(hào)之間有乘號(hào)(*),所以計(jì)算前面兩個(gè)(++i)之后,必須進(jìn)行乘法計(jì)算,這就是優(yōu)先級(jí)中的乘法計(jì)算,自左向右計(jì)算。所以結(jié)果變?yōu)榱?12 * 12的最終結(jié)果在和第三個(gè)括號(hào)的(++i)計(jì)算,就是144 * (++ i) = 144 * 13;
所以MUL(++i)的結(jié)果如下:
總結(jié):
慎用宏在計(jì)算方面的,但是宏的有點(diǎn)還是很多的,對(duì)于C語(yǔ)言來(lái)說(shuō),宏可以減少運(yùn)行的時(shí)間。在C++中,宏由于不會(huì)對(duì)類型進(jìn)行檢查,安全性不夠,所以建議使用const來(lái)
進(jìn)行使用,這樣可以保證類型一致。這是C/C++對(duì)宏的嚴(yán)謹(jǐn)性進(jìn)行優(yōu)化的結(jié)果。
以上所述是小編給大家介紹的C/C++中宏(#define)定義知識(shí),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
用C++類實(shí)現(xiàn)單向鏈表的增刪查和反轉(zhuǎn)操作方法
下面小編就為大家?guī)?lái)一篇用C++類實(shí)現(xiàn)單向鏈表的增刪查和反轉(zhuǎn)操作方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04C++右值引用與move和forward函數(shù)的使用詳解
為了支持移動(dòng)操作,新標(biāo)準(zhǔn)引入了一種新的引用類型——右值引用(rvalue reference)。所謂右值引用就是必須綁定到右值的引用,這篇文章主要介紹了C++右值引用與move和forward的使用2022-08-08C++制作鼠標(biāo)連點(diǎn)器實(shí)例代碼
大家好,本篇文章主要講的是C++制作鼠標(biāo)連點(diǎn)器實(shí)例代碼,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2022-01-01Qt圖形圖像開發(fā)之曲線圖表模塊QChart庫(kù)一個(gè)chart中顯示兩條曲線詳細(xì)方法與實(shí)例
這篇文章主要介紹了Qt圖形圖像開發(fā)之曲線圖表模塊QChart庫(kù)一個(gè)chart中顯示兩條曲線詳細(xì)方法與實(shí)例,需要的朋友可以參考下2020-03-03使用C語(yǔ)言實(shí)現(xiàn)CRC校驗(yàn)的方法
本篇文章是對(duì)使用C語(yǔ)言實(shí)現(xiàn)CRC校驗(yàn)的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05