一、宏定義#define
優點:一方面可以節省程式的空間上的篇幅,另外,恰當地使用宏定義可提高程式的時間效率。代碼可以寫的通俗易懂。可以提高程式的清晰性、可讀性,使于修改移植等。
缺點:宏定義的使用實際上也存在副作用,大量的使用會破壞程式的可讀性,并給程式的調試帶來麻煩,是優點也是缺點。過多的宏定義,代碼不容易調試,代碼進不去宏定義目前所運作的内容。
一般來說,如果一個函數非常大,一般不宜采用宏定義來進行改造,僅僅是那些小的函數,而且非常影響效率的函數才值得這樣去做。
1. 不帶參宏定義
例如: #define MAX 1000
(1)宏名一般用大寫
(2)使用宏可提高程式的通用性和易讀性,減少不一緻性,減少輸入錯誤和便于修改。例如:數組大小常用宏定義
(3)預處理是在編譯之前的處理,而編譯工作的任務之一就是文法檢查,預處理不做文法檢查。
(4)宏定義末尾不加分号;
(5)宏定義寫在函數的花括号外邊,作用域為其後的程式,通常在檔案的最開頭。
(6)可以用#undef指令終止宏定義的作用域
(7)宏定義可以嵌套
(8)字元串" "中永遠不包含宏
2.帶參的宏定義
例如:#define ADD(x,y) ((x)+(y))
1)實參如果是表達式容易出問題
#define S(r) r*r
area=S(a+b);第一步換為area=r*r;,第二步被換為area=a+b*a+b;
正确的宏定義是#define S(r) (r)*(r)
(2)宏名和參數的括号間不能有空格
(3)宏替換隻作替換,不做計算,不做表達式求解
(4)函數調用在編譯後程式運作時進行,并且配置設定記憶體。宏替換在編譯前進行,不配置設定記憶體
(5)宏的啞實結合不存在類型,也沒有類型轉換。
(6)函數隻有一個傳回值,利用宏則可以設法得到多個值
(7)宏展開使源程式變長,函數調用不會
(8)宏展開不占運作時間,隻占編譯時間,函數調用占運作時間(配置設定記憶體、保留現場、值傳遞、傳回值)
(9)宏定義不配置設定記憶體,變量定義配置設定記憶體。宏替換發生的過程
二、 宏展開過程
為了了解#define的作用,讓我們來了解一下對C語言源程式的處理過程。當我們在一個內建的開發環境如Turbo C中将編寫好的源程式進行編譯時,實際經過了預處理、編譯、彙編和連接配接幾個過程,見圖。

圖1 C語言的編譯過程
三、預處理器功能
其中預處理器産生編譯器的輸出,它實作以下的功能:
(1) 檔案包含
可以把源程式中的#include 擴充為檔案正文,即把包含的.h檔案找到并展開到#include 所在處。
(2) 條件編譯
預處理器根據#if和#ifdef等編譯指令及其後的條件,将源程式中的某部分包含進來或排除在外,通常把排除在外的語句轉換成空行。
(3) 宏展開
預處理器将源程式檔案中出現的對宏的引用展開成相應的宏 定義,即本文所說的#define的功能,由預處理器來完成。
經過預處理器處理的源程式與之前的源程式有所有不同,在這個階段所進行的工作隻是純粹的替換與展開,沒有任何計算功能,是以在學習#define指令時隻要能真正了解這一點,這樣才不會對此指令引起誤解并誤用。
四、樣例貼代碼
// 直接替換
#define max 1000
// ##和# 的使用,##連結,#把字元變為字元串
#define test(classname,len,type)\
char* unit_test_binary_to_geometry_service_pid = "pj."#classname#len#type"id";\
#define str(x) #x
// 傳回一個字元
#define getch(c) #@c
// 定義一個某類型的變量名稱。
#define cat(x,y) x##y
void main()
{
string str_ = str(waht);
char* tmp_cat = "this is a test";
string cat(var,1235);
var1235 = tmp_cat;
char ch_ = ch(t);
test(A,12,int)
string temp = unit_test_pid;
}
自己的用例:
#define unit_test_marco_derived_start(test_class_name,test_class_service_name,test_class_service_pid)\
test_class_service_name * ___##test_class_service_name;\
void test_unit_module (unit_test_writer::ptr test_writer_);\
static char* unit_test_##test_class_service_pid = "rw.unit.test."#test_class_name;\
\
class unit_test_##test_class_name\
:public unit_test\
{\
public:\
typedef rw_shared_ptr< unit_test_##test_class_name > ptr;\
typedef rw_shared_ptr<const unit_test_##test_class_name > const_ptr;\
\
unit_test_##test_class_name (unit_test_service* test_service_,runtime* runtime_)\
: _unit_test_service( test_service_ )\
, _runtime( runtime_ )\
{\
___##test_class_service_name = ( test_class_service_name * ) _runtime->get_service( test_class_service_pid )->get_service();\
}\
virtual ~ unit_test_##test_class_name (){}\
\
virtual void test(unit_test_result::ptr test_result_, unit_test_writer::ptr test_writer_)\
{\
test_writer_->write("\n -----------------start to test "#test_class_name"...---------------------\n");\
test_unit_module (test_writer_);\
test_writer_->write("\n -----------------end to test "#test_class_name"...---------------------\n");\
return;\
}\
private:\
unit_test_service* _unit_test_service;\
runtime* _runtime;\
private:\
};
當然宏定義的用法不止這麼點,多種多樣。
五、預處理指令
對于預處理指令,還有很多。也把别人的貼出來供各位參考:
宏定義不配置設定記憶體,變量定義配置設定記憶體。宏替換發生的過程
預處理指令由#(hash字元)開頭, 它獨占一行, #之前隻能是空白符. 以#開頭的語句就是預處理指令, 不以#開頭的語句為C中的代碼行. 常用的預處理指令如下:
#define 定義一個預處理宏
#undef 取消宏的定義
#include 包含檔案指令
#include_next 與#include相似, 但它有着特殊的用途
#if 編譯預進行中的條件指令, 相當于C文法中的if語句
#ifdef 判斷某個宏是否被定義, 若已定義, 執行随後的語句
#ifndef 與#ifdef相反, 判斷某個宏是否未被定義
#elif 若#if, #ifdef, #ifndef或前面的#elif條件不滿足, 則執行#elif之後的語句, 相當于C文法中的else-if
#else 與#if, #ifdef, #ifndef對應, 若這些條件不滿足, 則執行#else之後的語句, 相當于C文法中的else
#endif #if, #ifdef, #ifndef這些條件指令的結束标志.
defined 與#if, #elif配合使用, 判斷某個宏是否被定義
#line 标志該語句所在的行号
# 将宏參數替代為以參數值為内容的字元竄常量
## 将兩個相鄰的标記(token)連接配接為一個單獨的标記
#pragma 說明編譯器資訊
#warning 顯示編譯警告資訊
#error 顯示編譯錯誤資訊
說明:近期用了一些宏定義,是以就抽空整理了網上的部分東西。
若有問題,請随時聯系!