青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-80  評論-24  文章-0  trackbacks-0

C(和C++)中的宏(Macro)屬于編譯器預(yù)處理的范疇,屬于編譯期概念(而非運(yùn)行期概念)。下面對常遇到的宏的使用問題做了簡單總結(jié)。

關(guān) 于#和##

在C語言的宏中,#的功能是將其后面的宏參數(shù)進(jìn)行字符串化操作(Stringfication),簡單說就是在對它所引用的宏 變量通過替換后在其左右各加上一個雙引號。比如下面代碼中的宏:

#define WARN_IF(EXP) \

do{ if (EXP) \

fprintf(stderr, "Warning: " #EXP "\n"); } \

while(0)

那么實(shí)際使用中會出現(xiàn)下面所示的替換過程:

WARN_IF (divider == 0);


被替換為


do {

if (divider == 0)

fprintf(stderr, "Warning" "divider == 0" "\n");

} while(0);

這樣每次divider(除數(shù))為0的時候便會在標(biāo) 準(zhǔn)錯誤流上輸出一個提示信息。

而## 被稱為連接符(concatenator),用來將兩個Token連接為一個Token。注意這里連接的對象是Token就行,而不一定是宏的變量。比如 你要做一個菜單項命令名和函數(shù)指針組成的結(jié)構(gòu)體的數(shù)組,并且希望在函數(shù)名和菜單項命令名之間有直觀的、名字上的關(guān)系。那么下面的代碼就非常實(shí)用:

struct command

{

char * name;

void (*function) (void);

};


#define COMMAND(NAME) { NAME, NAME ## _command }


// 然后你就用一些預(yù)先定義好的命令來方便的初始化一個command結(jié)構(gòu)的數(shù)組了:


struct command commands[] = {

COMMAND(quit),

COMMAND(help),

...

}

COMMAND宏在這里充當(dāng)一個代碼生成器的作 用,這樣可以在一定程度上減少代碼密度,間接地也可以減少不留心所造成的錯誤。我們還可以n個##符號連接 n+1個Token,這個特性也是#符號所不具備的。比如:

#define LINK_MULTIPLE(a,b,c,d) a##_##b##_##c##_##d


typedef struct _record_type LINK_MULTIPLE(name,company,position,salary);

// 這里這個語句將展開為:

// typedef struct _record_type name_company_position_salary;

關(guān) 于...的使用

...在C宏中稱為Variadic Macro,也就是變參宏。比如:

#define myprintf(templt,...) fprintf(stderr,templt,__VA_ARGS__)


// 或者


#define myprintf(templt,args...) fprintf(stderr,templt,args)

第 一個宏中由于沒有對變參起名,我們用默認(rèn)的宏__VA_ARGS__來替代它。第二個宏中,我們顯式地命名變參為args,那么我們在宏定義中就可以用 args來代指變參了。同C語言的stdcall一樣,變參必須作為參數(shù)表的最有一項出現(xiàn)。當(dāng)上面的宏中我們只能提供第一個參數(shù)templt時,C標(biāo)準(zhǔn)要 求我們必須寫成:

myprintf(templt,);

的形式。這時的替換過程為:

myprintf("Error!\n",);


替換為:



fprintf(stderr,"Error!\n",);

這是一個 語法錯誤,不能正常編譯。這個問題一般有兩個解決方法。首先,GNU CPP提供的解決方法允許上面的宏調(diào)用寫成:

myprintf(templt);

而 它將會被通過替換變成:

fprintf(stderr,"Error!\n",);

很明顯,這里仍然會產(chǎn)生編譯錯誤(非 本例的某些情況下不會產(chǎn)生編譯錯誤)。除了這種方式外,c99和GNU CPP都支持下面的宏定義方式:

#define myprintf(templt, ...) fprintf(stderr,templt, ##__VAR_ARGS__)

這 時,##這個連接符號充當(dāng)?shù)淖饔镁褪钱?dāng)__VAR_ARGS__為空的時候,消除前面的那個逗號。那么此時的翻譯過程如下:

myprintf(templt);


被轉(zhuǎn)化為:


fprintf(stderr,templt);

這樣如果templt合法,將不會產(chǎn)生 編譯錯誤。 這里列出了一些宏使用中容易出錯的地方,以及合適的使用方式。

錯誤的嵌套-Misnesting

宏的定義不一定要有完整的、配對的括號,但是為了避免出錯并且提高可讀性,最好避免這樣使用。

由 操作符優(yōu)先級引起的問題-Operator Precedence Problem

由于宏只是簡單的替換,宏的參數(shù)如果是復(fù)合結(jié)構(gòu),那么 通過替換之后可能由于各個參數(shù)之間的操作符優(yōu)先級高于單個參數(shù)內(nèi)部各部分之間相互作用的操作符優(yōu)先級,如果我們不用括號保護(hù)各個宏參數(shù),可能會產(chǎn)生預(yù)想不 到的情形。比如:

#define ceil_div(x, y) (x + y - 1) / y

那么

a = ceil_div( b & c, sizeof(int) );

將被轉(zhuǎn)化為:

a = ( b & c + sizeof(int) - 1) / sizeof(int);

// 由于+/-的優(yōu)先級高于&的優(yōu)先級,那么上面式子等同于:

a = ( b & (c + sizeof(int) - 1)) / sizeof(int);

這顯然不是調(diào)用者的初衷。為了避免這種情況發(fā)生,應(yīng)當(dāng)多寫幾個括號:

#define ceil_div(x, y) (((x) + (y) - 1) / (y))

消除多余的分號-Semicolon Swallowing

通常情況下,為了使函數(shù)模樣的宏在表面上看起來像一個通常的C語言調(diào)用一樣,通常情況下我們在宏的后面加上一個分 號,比如下面的帶參宏:

MY_MACRO(x);

但是如果是下面的情況:

#define MY_MACRO(x) { \

/* line 1 */ \

/* line 2 */ \

/* line 3 */ }



//...


if (condition())

MY_MACRO(a);

else

{...}

這樣會由于多出的那個分號產(chǎn)生編譯錯誤。為了避免這種情況出現(xiàn)同時保持MY_MACRO(x);的這種寫法,我們 需要把宏定義為這種形式:

#define MY_MACRO(x) do {

/* line 1 */ \

/* line 2 */ \

/* line 3 */ } while(0)

這樣只要保證總是使用分號,就不會有任何問題。

Duplication of Side Effects

這里的Side Effect是指宏在展開的時候?qū)ζ鋮?shù)可能進(jìn)行多次Evaluation(也就是取值),但是如果這個宏參數(shù)是一個函數(shù),那么就有可能被調(diào)用多次從而達(dá) 到不一致的結(jié)果,甚至?xí)l(fā)生更嚴(yán)重的錯誤。比如:

#define min(X,Y) ((X) > (Y) ? (Y) : (X))


//...



c = min(a,foo(b));

這 時foo()函數(shù)就被調(diào)用了兩次。為了解決這個潛在的問題,我們應(yīng)當(dāng)這樣寫min(X,Y)這個宏:

#define min(X,Y) ({ \

typeof (X) x_ = (X); \

typeof (Y) y_ = (Y); \

(x_ < y_) ? x_ : y_; })

({...})的作用是將內(nèi)部的幾條語句中最后一條的值返回,它也允許在內(nèi)部聲明變量(因為它通過大括號組成了一個局部 Scope)。

==

#define display(name) printf(""#name"") 
int main() { 
display(name); 

運(yùn)行結(jié)果是name,為什么不是"#name"呢? 
--------------------------------------------------------------- 

#在這里是字符串化的意思 
printf(""#name"") 相當(dāng)于 
printf("" "name" "") 
--------------------------------------------------------------- 

The number-sign or "stringizing" operator (#) converts macro parameters (after expansion) to string constants
--------------------------------------------------------------- 

printf("" #name "") <1> 
相當(dāng)于printf("" "name" "") <2> 
而<2>中的第2,3個“中間時空格 等價于("空+name+空') 
--------------------------------------------------------------- 

## 連接符與# 符 

## 連接符號由兩個井號組成,其功能是在帶參數(shù)的宏定義中將兩個子串(token)聯(lián)接起來,從而形成一個新的子串。但它不可以是第一個或者最后一個子串。所 謂的子串 (token)就是指編譯器能夠識別的最小語法單元。具體的定義在編譯原理里有詳盡的解釋,但不知道也無所謂。同時值得注意的是#符是把傳遞過來的參數(shù)當(dāng) 成字符串進(jìn)行替代。下面來看看它們是怎樣工作的。這是MSDN上的一個例子。 

假設(shè)程序中已經(jīng)定義了這樣一個帶參數(shù)的宏: 
#define paster( n ) printf( "token" #n " = %d", token##n ) 

同時又定義了一個整形變 量: 
int token9 = 9; 

現(xiàn)在在主程序中以下面的方式調(diào)用這個宏: 
paster( 9 ); 

那 么在編譯時,上面的這句話被擴(kuò)展為: 
printf( "token" "9" " = %d", token9 ); 

注意到 在這個例子中,paster(9);中的這個”9”被原封不動的當(dāng)成了一個字符串,與”token”連接在了一起,從而成為了token9。而#n也 被”9”所替代。 

可想而知,上面程序運(yùn)行的結(jié)果就是在屏幕上打印出token9=9 
--------------------------------------------------------------- 

#define display(name) printf(""#name"") 
int main() { 
display(name); 

==================================== 
特殊性就在 于它是個宏,宏里面處理#號就如LS所說! 
處理后就是一個附加的字符串! 

但printf(""#name"") ;就不行了! 
--------------------------------------------------------------- 

#define display(name) printf(""#name"") 

該定義 字符串化name, 
得 到結(jié)果其實(shí)就是 printf("name") 
(前后的空字符串拿掉) 

這樣輸出來的自然是 name 

從另 外一個角度講, 
#是一個連接符號, 
參與運(yùn)算了, 自然不會輸出了 ...

posted on 2011-01-18 16:58 myjfm 閱讀(2367) 評論(0)  編輯 收藏 引用 所屬分類: c/c++基礎(chǔ)
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲图片在区色| 久久不射2019中文字幕| 免费在线欧美黄色| 久久精品二区| 在线看国产日韩| 免费在线观看成人av| 久久偷看各类wc女厕嘘嘘偷窃| 很黄很黄激情成人| 美国成人直播| 欧美成在线视频| 99精品99| 先锋a资源在线看亚洲| 国产一区三区三区| 免费在线成人av| 欧美国产日本在线| 亚洲一区欧美| 欧美一级免费视频| 亚洲国产日韩在线一区模特| 亚洲激情网站免费观看| 欧美日韩综合在线免费观看| 欧美一区二区三区免费在线看| 性久久久久久| 亚洲国产日韩在线| 一区二区三区免费观看| 国产亚洲欧美激情| 亚洲精品久久久久久下一站 | 欧美成人自拍| 欧美激情一二三区| 午夜精品短视频| 久久人人爽人人爽爽久久| 日韩一本二本av| 亚洲欧美日韩成人高清在线一区| 精品成人一区二区三区四区| 亚洲精品久久久久久久久久久久久| 国产精品高潮久久| 欧美成年人视频网站欧美| 欧美色一级片| 亚洲电影免费观看高清完整版在线| 欧美日韩午夜在线| 免费一级欧美片在线观看| 国产精品扒开腿做爽爽爽视频 | 在线免费观看日韩欧美| 99精品视频网| 亚洲人成网站在线观看播放| 亚洲你懂的在线视频| 亚洲日本中文字幕免费在线不卡| 性娇小13――14欧美| 亚洲色诱最新| 欧美黄在线观看| 男男成人高潮片免费网站| 国产精品一区二区在线观看| 日韩视频在线免费| 亚洲人永久免费| 久久久视频精品| 久久久久久一区二区| 国产精品乱码人人做人人爱| 亚洲精品欧洲| 亚洲人成网站在线观看播放| 久久婷婷人人澡人人喊人人爽 | 国产一区二区三区免费不卡| 一区二区三区精品| av成人激情| 欧美另类变人与禽xxxxx| 欧美不卡视频一区| 悠悠资源网亚洲青| 久久精品国产亚洲高清剧情介绍| 久久国产夜色精品鲁鲁99| 国产精品一区二区在线观看不卡| 中文日韩在线| 亚洲综合清纯丝袜自拍| 国产精品激情av在线播放| 夜夜狂射影院欧美极品| 中文欧美在线视频| 欧美午夜在线视频| 艳妇臀荡乳欲伦亚洲一区| 亚洲香蕉成视频在线观看| 欧美视频中文在线看| 在线天堂一区av电影| 亚洲欧美国产三级| 国产日本欧美一区二区三区在线| 欧美一二三区在线观看| 久久亚洲视频| 亚洲第一伊人| 欧美久久久久中文字幕| 99成人免费视频| 香蕉精品999视频一区二区| 国产视频一区在线观看一区免费 | 欧美wwwwww| 亚洲精品免费一二三区| 欧美日韩精品系列| 亚洲影院免费观看| 久久久久久久网站| 亚洲精品久久视频| 国产精品国色综合久久| 久久av最新网址| 亚洲国产欧美一区二区三区丁香婷| 亚洲六月丁香色婷婷综合久久| 欧美午夜在线视频| 欧美一区91| 亚洲精品久久久久中文字幕欢迎你 | 一本到12不卡视频在线dvd| 亚洲欧美日韩电影| 国产最新精品精品你懂的| 欧美成人日韩| 亚洲女同精品视频| 亚洲第一搞黄网站| 午夜精品999| 91久久极品少妇xxxxⅹ软件| 国产精品mv在线观看| 久久久久久久国产| 中文亚洲字幕| 欧美大秀在线观看| 先锋影音一区二区三区| 亚洲欧洲视频在线| 国内精品久久久| 国产精品成人国产乱一区| 久久综合网hezyo| 亚洲小视频在线观看| 亚洲黄色成人| 免费高清在线一区| 午夜视频在线观看一区二区三区| 亚洲精品欧美日韩| 国产欧美日韩一区二区三区| 欧美日韩日本国产亚洲在线| 久久九九精品| 性欧美xxxx视频在线观看| 日韩性生活视频| 亚洲电影视频在线| 毛片av中文字幕一区二区| 性做久久久久久免费观看欧美| 亚洲娇小video精品| 国产一区深夜福利| 国产精品尤物福利片在线观看| 欧美黑人一区二区三区| 久久久久久久久久久成人| 亚洲欧美精品在线观看| 在线天堂一区av电影| 亚洲精品视频免费观看| 亚洲高清免费视频| 欧美激情在线有限公司| 久久夜色精品亚洲噜噜国产mv| 欧美一区二区啪啪| 欧美一区2区三区4区公司二百| 亚洲一区二区三区中文字幕| 这里只有精品丝袜| 一本色道久久88亚洲综合88| 99视频热这里只有精品免费| 亚洲精品日韩在线| 日韩午夜黄色| 一本不卡影院| 中国成人在线视频| 亚洲欧美成人一区二区三区| 亚洲欧美日韩直播| 欧美亚洲视频在线观看| 欧美一区二区在线免费播放| 久久不见久久见免费视频1| 欧美在线国产| 久久伊人亚洲| 欧美黄免费看| 亚洲美女av在线播放| 一区二区三区视频在线| 亚洲天堂av图片| 欧美一区二区久久久| 久久久999精品| 欧美中文字幕在线| 欧美激情亚洲自拍| 女生裸体视频一区二区三区| 亚洲日韩欧美视频一区| 一本大道久久精品懂色aⅴ| 久久一区中文字幕| 亚洲欧美综合v| 欧美日韩国产天堂| 亚洲欧洲另类国产综合| 久久婷婷一区| 亚欧成人在线| 国产精品日本欧美一区二区三区| 日韩午夜av在线| 欧美激情中文不卡| 久久久久久久久久久久久久一区| 国产精品一区二区在线观看不卡| 在线中文字幕一区| 亚洲人体大胆视频| 欧美v国产在线一区二区三区| 国内自拍一区| 久久精品国产999大香线蕉| 亚洲视频一起| 国产精品久久久久久久久免费| 夜夜狂射影院欧美极品| 亚洲黄网站黄| 欧美人与禽猛交乱配| 亚洲人成网站精品片在线观看| 美国成人直播| 蜜桃av噜噜一区二区三区| 亚洲高清影视| 亚洲国产精品久久91精品| 久久夜色精品国产欧美乱极品| 在线电影国产精品| 蜜臀久久久99精品久久久久久| 久久久亚洲国产天美传媒修理工| 亚洲第一区在线观看|