新聞中心
宏和函數(shù)的區(qū)別以及C語言的編譯鏈接過程
宏在編譯之前,需要進(jìn)行預(yù)處理,將宏直接提換成宏定義的代碼,是直接替換,也就是說,在預(yù)處理之后,你再看代碼,發(fā)現(xiàn)宏定義已經(jīng)被替換過來了,你看到是你定義之后的那一串代碼。
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項目有:域名與空間、網(wǎng)站空間、營銷軟件、網(wǎng)站建設(shè)、西區(qū)網(wǎng)站維護(hù)、網(wǎng)站推廣。
而函數(shù),在編譯之后,有一系列調(diào)用函數(shù)的過程,比如,傳參,壓棧等,這部分是編譯器所做的。
C 語言編譯鏈接過程:
test.c(原始代碼) -- 預(yù)處理 -- test.i(經(jīng)過預(yù)處理的)-- 編譯 -- test.s(匯編代碼)-- 匯編 -- test.o(目標(biāo)文件,其實這部分已經(jīng)是單個文件的完整二進(jìn)制文件了,只是還不能執(zhí)行,如果不懂這句話,可以再問我,其實這部分知識,平時也很少遇到) -- 鏈接 -- test (可執(zhí)行文件,比如一個程序由3個代碼文件共同生成,那么就會有3個.o格式目標(biāo)文件,鏈接是把多個目標(biāo)文件真正的聯(lián)系在一起,比如a.o 中使用了 b.o中的一個函數(shù),那么它們兩個之間的地址是如何確定的(同理,可引申到使用函數(shù)庫的問題,使用printf函數(shù),也是需要鏈接器進(jìn)行確定printf函數(shù)地址,才能知道如何調(diào)用。)這個就是鏈接器的作用)
C語言中帶參數(shù)的宏定義與函數(shù)的區(qū)別(試舉例)
宏只是字符的替換,在預(yù)處理階段就給替換到代碼中去了比如下面的代碼
#include
#define
MAX(x,
y)
((x)(y)?(x):y())
int
main()
{
int
a
=
2,
b
=
4;
int
m;
m
=
MAX(2,
4);
printf("%d\n",
m);
return
0;
}
如果你用的是gcc編譯器,執(zhí)行
gcc
-E
main.c
-o
main.i,打開main.i文件就可以看到他是如何替換進(jìn)去的,直接拖到最后,前面的都是stdio.h中的內(nèi)容。
int
main()
{
int
a
=
2,
b
=
4;
int
m;
m
=
((2)(4)?(2):4());
printf("%d\n",
m);
return
0;
}
函數(shù)就不同了,函數(shù)還需要分配??臻g,在執(zhí)行函數(shù)時都要進(jìn)行入棧和出棧操作,有的還需要分配堆空間。
宏所實現(xiàn)的功能有限,而且長代碼不易讀,但是對于邏輯簡單、代碼不長、經(jīng)常使用的功能由宏來實現(xiàn)是個不錯的選擇
c語言宏定義和函數(shù)的區(qū)別
不管是宏定義還是函數(shù),都不要在修改某個變量之后,在同一個表達(dá)式中的另一個地方讀取這個變量的值。否則結(jié)果就是未定義的
對于你的代碼,在下面的表達(dá)式中
printf("%d^2?=?%d\n",?(i-1),?SQ(i++))
//?????????????????????1????????2
標(biāo)有 2 的地方修改了變量 i 的值,標(biāo)有 1 的地方又嘗試讀取 i 的值。你可能以為 1 在 2 之前計算。然而——你以為你以為的就是你以為的?
c語言,宏定義,與函數(shù)的差別 我覺得宏定義和函數(shù)沒什么差別啊, 是否可以用宏定義代替函數(shù)
不同。
雖然功能近似,但函數(shù)會產(chǎn)生獨立代碼,每次調(diào)用執(zhí)行的是同一個位置的代碼,無論調(diào)用多少次。
宏定義是簡單的文本替換,產(chǎn)生的代碼是替換后程序產(chǎn)生的代碼,簡單說就是程序里每次使用宏替換后的地方都要產(chǎn)生類似的代碼,而這些替換后產(chǎn)生的代碼存在于程序的不同位置。
宏定義不檢查參數(shù)類型,僅僅是簡單的文本替換
我想知道c語言里面怎么區(qū)分函數(shù)與宏
在C及C++語言中允許用一個標(biāo)識符來表示一個字符串,稱為宏,該字符串可以是常數(shù)、表達(dá)式、格式串等。在編譯預(yù)處理時,對程序中所有出現(xiàn)的“宏名”,都用宏定義中的字符串去代換,這稱為“宏代換”或“宏展開”。宏定義是由源程序中的宏定義命令完成的。宏代換是由預(yù)處理程序自動完成的。若字符串是表達(dá)式,我們稱之為函數(shù)式宏定義,那函數(shù)式宏定義與普通函數(shù)有什么區(qū)別呢?我們以下面兩行代碼為例,展開描述:
函數(shù)式宏定義:#define MAX(a,b) ((a)(b)?(a):(b))
普通函數(shù) : MAX(a,b) { return ab?a:b;}
(1)函數(shù)式宏定義的參數(shù)沒有類型,預(yù)處理器只負(fù)責(zé)做形式上的替換,而不做參數(shù)類型檢查,所以傳參時要格外小心。
(2)調(diào)用真正函數(shù)的代碼和調(diào)用函數(shù)式宏定義的代碼編譯生成的指令不同。
如果MAX是個普通函數(shù),那么它的函數(shù)體return a b ? a : b; 要編譯生成指令,代碼中出現(xiàn)的每次調(diào)用也要編譯生成傳參指令和call指令。而如果MAX是個函數(shù)式宏定義,這個宏定義本身倒不必編譯生成指令,但是代碼中出現(xiàn)的每次調(diào)用編譯生成的指令都相當(dāng)于一個函數(shù)體,而不是簡單的幾條傳參指令和call指令。所以,使用函數(shù)式宏定義編譯生成的目標(biāo)文件會比較大。
(3)函數(shù)式宏定義要注意格式,尤其是括號。
如果上面的函數(shù)式宏定義寫成 #define MAX(a, b) (ab?a:b),省去內(nèi)層括號,則宏展開就成了k = (i0x0fj0x0f?i0x0f:j0x0f),運算的優(yōu)先級就錯了。同樣道理,這個宏定義的外層括號也是不能省的。若函數(shù)中是宏替換為 ++MAX(a,b),則宏展開就成了 ++(a)(b)?(a):(b),運算優(yōu)先級也是錯了。
(4)若函數(shù)參數(shù)為表達(dá)式,則普通函數(shù)的調(diào)用與函數(shù)式宏定義的替換過程是不一樣的。
普通函數(shù)調(diào)用時先求實參表達(dá)式的值再傳給形參,如果實參表達(dá)式有Side Effect,那么這些SideEffect只發(fā)生一次。例如MAX(++a, ++b),如果MAX是普通函數(shù),a和b只增加一次。但如果MAX函數(shù)式宏定義,則要展開成k = ((++a)(++b)?(++a):(++b)),a和b就不一定是增加一次還是兩次了。所以若參數(shù)是表達(dá)式,替換函數(shù)式宏定義時一定要仔細(xì)看好。
(5)函數(shù)式宏定義往往會導(dǎo)致較低的代碼執(zhí)行效率。
看下面一段代碼:
int a[]={9,3,5,2,1,0,8,7,6,4};
int max(n)
{
return n==0?a[0]:MAX(a[n],max(n-1));
}
int main()
{
max(9);
return 0;
}
若是普通函數(shù),則通過遞歸,可取的最大值,時間復(fù)雜度為O(n)。但若是函數(shù)式宏定義,則宏展開為( a[n]max(n-1)?a[n]:max(n-1) ),其中max(n-1)被調(diào)用了兩遍,這樣依此遞歸下去,時間復(fù)雜度會很高。
盡管函數(shù)式宏定義和普通函數(shù)相比有很多缺點,但只要小心使用還是會顯著提高代碼的執(zhí)行效率,畢竟省去了分配和釋放棧幀、傳參、傳返回值等一系列工作,因此那些簡短并且被頻繁調(diào)用的函數(shù)經(jīng)常用函數(shù)式宏定義來代替實現(xiàn)。
C語言中宏函數(shù)跟自定義的函數(shù)有什么區(qū)別?
可以把宏理解成拼字游戲,它功能很強(qiáng)大,但是強(qiáng)大到使用不好就會有副作用。C++有很多語言設(shè)施用來完全特定功能的宏,如const,inline,template,就是為了讓大家少用宏。給你舉個宏和函數(shù)不同的例子代碼:
#define max(x,y) ((x)(y)?(x):(y))
template class T
inline T max(T x,T y){return xy?x:y;}
看起來似乎是相同的功能,可是函數(shù)調(diào)用,畢竟會求完每一個實參的值,再傳遞給被調(diào)函數(shù),即使聲明了inline,在調(diào)用點展開而不發(fā)生實際的調(diào)用開銷。
但是你試試用這個調(diào)用宏,結(jié)果就會有問題:
int i=4,j=5;
int k=max(i++,j++);
如果是函數(shù)調(diào)用,i==5,j==6,k==5。如果是宏的話,結(jié)果是:
int k=((i++)(j++)?(i++):(j++));
你覺得會一樣嗎?所以,慎用宏。
MFC中有很多功能是宏完成的,它太強(qiáng)大了,很多情況下有宏很高效,但是不容易控制。
網(wǎng)站欄目:c語言函數(shù)和宏定義的區(qū)別,c語言函數(shù)和宏定義的區(qū)別與聯(lián)系
轉(zhuǎn)載注明:http://www.dlmjj.cn/article/hdpeoe.html