46 函式與巨集分析

2021-10-02 10:06:29 字數 4668 閱讀 6829

注:部落格中內容主要來自《狄泰軟體學院》,部落格僅當私人筆記使用。

測試環境:ubuntu 10.10

gcc版本:4.4.5

一、函式與巨集

巨集or函式?

#define reset(p,len)    \

while(len > 0) \

((char*)p)[--len] = 0

void reset(void* p, int len)

二、函式與巨集

1) 巨集是由預處理器直接替換展開的,編譯器不知道巨集的存在

2) 函式是由編譯器直接編譯的實體,呼叫行為由編譯器決定

3) 多次使用巨集會導致最終可執行程式的體積增大(盡量封裝成乙個函式,減少程式體積)

4) 函式是跳轉執行的,記憶體中只有乙份函式體存在

(函式呼叫發生時會去定義函式的地方執行)

5) 巨集的效率比函式要高,因為是直接展開,無呼叫開銷

6) 函式呼叫時會建立活動記錄,效率不如巨集

程式設計實驗

函式與巨集

46-1.c

#include #define reset(p, len) \

while( len > 0 ) \

((char*)p)[--len] = 0

void reset(void* p, int len)

int main()

; int len = sizeof(array);

int i = 0;

reset(array, len);

for(i=0; i<5; i++)

return 0;

}

操作:

1) 使用reset(array, len):gcc 46-1.c -o 46-1.out編譯正確,列印結果:

array[0] = 0

array[1] = 0

array[2] = 0

array[3] = 0

array[4] = 0

2) 使用reset(6, len)

#include #define reset(p, len)          \

while( len > 0 ) \

((char*)p)[--len] = 0

void reset(void* p, int len)

int main()

; int len = sizeof(array);

int i = 0;

reset(6, len);

for(i=0; i<5; i++)

return 0;

}

gcc 46-1.c -o 46-1.out編譯正確,執行錯誤:

segmentation fault (core dumped)
分析:

巨集定義不對語法進行檢查。

3) 使用reset(6, len)

#include #define reset(p, len)          \

while( len > 0 ) \

((char*)p)[--len] = 0

void reset(void* p, int len)

int main()

; int len = sizeof(array);

int i = 0;

reset(6, len);

for(i=0; i<5; i++)

return 0;

}

gcc 46-1.c -o 46-1.out編譯錯誤:

46-1.c: in function 『main』:

46-1.c:19:2: warning: passing argument 1 of 『reset』 makes pointer from integer without a cast [enabled by default]

reset(6, len);

^警告:編譯函式reset的第乙個引數時,應該是指標型別但卻是整型

46-1.c:7:6: note: expected 『void *』 but argument is of type 『int』

void reset(void* p, int len)

^

7)巨集的效率比函式稍高,但是其***巨大

8) 巨集是文字替換,引數無法進行型別檢查

9) 可以用函式完成的功能絕對不用巨集

10) 巨集的定義中不能出現遞迴定義

例項分析

巨集的***

46-2.c

#include #define _add_(a, b) a + b //_開頭?

#define _mul_(a, b) a * b

#define _min_(a, b) ((a) < (b) ? (a) : (b))

int main()

操作:

1) gcc 46-2.c -o 46-2.out編譯正常,列印結果:

11

2

2) 注釋掉#include ,預編譯:gcc -e 46-2.c -o 46-2.i,開啟46-2.i檔案:

# 1 "46-2.c"

# 1 ""

# 1 ""

# 1 "/usr/include/stdc-predef.h" 1 3 4

# 1 "" 2

# 1 "46-2.c"

int main()

分析:

巨集不對語法進行檢查,隱患很大,解決辦法:內聯函式。

巨集的妙用

1) 用於生成一些常規性的**

2) 封裝函式,加上型別資訊

例項分析

巨集的妙用

46-3.c

#include #include #define malloc(type, x) (type*)malloc(sizeof(type)*x)

#define free(p) (free(p), p=null)

//格式化輸出,#是把巨集轉換成字串

#define log_int(i) printf("%s = %d\n", #i, i)

#define log_char(c) printf("%s = %c\n", #c, c)

#define log_float(f) printf("%s = %f\n", #f, f)

#define log_pointer(p) printf("%s = %p\n", #p, p)

#define log_string(s) printf("%s = %s\n", #s, s)

//為了簡化寫for迴圈

#define foreach(i, n) while(1) break; }

int main()

操作:

1) gcc 46-3.c -o 46-3.out編譯正確,列印結果:

str = d.t.software

pi = 0x9405008

value = 1

value = 2

value = 3

value = 4

value = 5

pi = (nil)

2) 注釋掉foreach:

#include #include #define malloc(type, x)   (type*)malloc(sizeof(type)*x)

#define free(p) (free(p), p=null)

//格式化輸出,#是把巨集轉換成字串

#define log_int(i) printf("%s = %d\n", #i, i)

#define log_char(c) printf("%s = %c\n", #c, c)

#define log_float(f) printf("%s = %f\n", #f, f)

#define log_pointer(p) printf("%s = %p\n", #p, p)

#define log_string(s) printf("%s = %s\n", #s, s)

//為了簡化寫for迴圈

#define foreach(i, n) while(1) break; }

int main()

gcc 46-3.o 46-3.out編譯正確,列印結果:

str = d.t.software

pi = 0x895a008

pi = (nil)

小結:

1) 巨集和函式並不是競爭對手

2) 巨集能夠接受任何型別的引數,效率高,易出錯

3) 函式的引數必須是固定型別,效率稍低,不易出錯

4) 巨集可以實現函式不能實現的功能

通過程式分析巨集,函式原型與定義函式

include define name gigathink,inc.define address 101 megabuck plaza define place megapolis,ca 94904 define width 40 void starbar void 函式原型 intmain voi...

函式 內聯函式與巨集

一 內聯函式與巨集的區別 內聯函式和巨集很類似,而區別在於,巨集是由預處理器對巨集進行替代,而內聯函式是通過編譯器控制來實現的。而且內聯函式是真正的函式,只是在需要用到的時候,內聯函式像巨集一樣的展開,所以取消了函式的引數壓棧,減少了呼叫的開銷。你可以象呼叫函式一樣來呼叫內聯函式,而不必擔心會產生於...

巨集與內聯函式

函式作為一種抽象機制,對解決大型複雜問題起到了很大作用。但是,由於函式呼叫時需要開銷的,例如,函式呼叫時需要保護呼叫者的執行環境,進行引數傳遞,執行呼叫命令,為區域性變數分配空間以及執行返回指令等,因此函式會帶來程式執行效率的下降,特別是對一些小函式的頻繁呼叫。c 提供了兩種解決上述問題的辦法 巨集...