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

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

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

關(guān) 于#和##

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

#define WARN_IF(EXP) \

do{ if (EXP) \

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

while(0)

那么實際使用中會出現(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)系。那么下面的代碼就非常實用:

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)

第 一個宏中由于沒有對變參起名,我們用默認的宏__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)先級,如果我們不用括號保護各個宏參數(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ù)可能進行多次Evaluation(也就是取值),但是如果這個宏參數(shù)是一個函數(shù),那么就有可能被調(diào)用多次從而達 到不一致的結(jié)果,甚至?xí)l(fā)生更嚴重的錯誤。比如:

#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); 

運行結(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) 成字符串進行替代。下面來看看它們是怎樣工作的。這是MSDN上的一個例子。 

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

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

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

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

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

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

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

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

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

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

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

這樣輸出來的自然是 name 

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

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>
            欧美精品一区二区精品网| 欧美日韩中文| 在线看视频不卡| 久久字幕精品一区| 久久久久久久91| 亚洲大胆人体在线| 亚洲国产精品精华液网站| 麻豆成人综合网| 亚洲精品欧美极品| 一本久久综合| 国产一区二区日韩精品欧美精品| 久久精品国产清高在天天线| 久久精品2019中文字幕| 亚洲国产一区二区三区高清| 亚洲国产精品一区二区第四页av | 亚洲国产精彩中文乱码av在线播放| 欧美一区二区在线视频| 在线观看日产精品| 亚洲第一二三四五区| 欧美日韩在线精品| 欧美一区二区视频网站| 久久久人成影片一区二区三区观看| 亚洲成在人线av| 99国产精品国产精品毛片| 国产精品一区在线播放| 欧美.www| 欧美午夜在线视频| 久久亚洲私人国产精品va| 欧美激情导航| 久久黄金**| 欧美成在线观看| 欧美在线视频观看| 欧美黑人多人双交| 久久精品国产69国产精品亚洲| 久久夜色撩人精品| 亚洲欧美日韩国产一区二区| 久久久夜夜夜| 香港久久久电影| 欧美激情一区二区三区四区| 欧美一区二区三区男人的天堂| 鲁大师影院一区二区三区| 性久久久久久久久久久久| 免费一级欧美片在线观看| 久久国产加勒比精品无码| 欧美精品久久一区| 女人色偷偷aa久久天堂| 国产精品久久久一区二区三区 | 91久久精品久久国产性色也91| 亚洲午夜精品| 一本到高清视频免费精品| 久久久精品一区| 亚洲——在线| 欧美日韩一区在线播放| 欧美高清日韩| 精品不卡在线| 欧美一区二区在线看| 性做久久久久久免费观看欧美| 欧美精品色一区二区三区| 欧美成人午夜影院| 极品少妇一区二区| 欧美一区免费视频| 久久国产精品久久久久久久久久 | 亚洲男人av电影| 亚洲一二三级电影| 欧美激情中文字幕在线| 欧美国产日本韩| 国内精品国产成人| 欧美主播一区二区三区美女 久久精品人| 在线亚洲国产精品网站| 欧美日本高清视频| 亚洲精品午夜精品| 日韩视频免费观看高清在线视频 | 性感少妇一区| 欧美综合国产| 国内自拍一区| 久久久精品日韩欧美| 免费亚洲电影| 亚洲激情国产精品| 欧美电影在线观看| 亚洲精品视频在线观看网站 | 国产精品草莓在线免费观看| 日韩视频在线观看一区二区| 一区二区欧美精品| 国产精品乱码久久久久久| 亚洲一区制服诱惑| 久久久爽爽爽美女图片| 韩国女主播一区| 美女图片一区二区| 亚洲精品视频免费| 性一交一乱一区二区洋洋av| 国产亚洲午夜| 免费观看国产成人| 日韩午夜在线| 久久精品国产清高在天天线| 在线日韩精品视频| 欧美日韩四区| 久久黄色影院| 亚洲国产日韩欧美在线图片 | 国产精品视频xxxx| 久久久av水蜜桃| 亚洲激情在线观看视频免费| 亚洲自拍偷拍色片视频| 国内精品久久国产| 欧美精品一区在线| 午夜精品久久久久久久| 欧美大秀在线观看| 亚洲欧美亚洲| 亚洲国产精品一区二区尤物区| 欧美日韩精品免费看| 久久国产福利国产秒拍| 亚洲黄色影院| 久久久精品2019中文字幕神马| 亚洲精品国精品久久99热一| 国产精品视屏| 欧美激情一二三区| 久久激情五月激情| 亚洲午夜视频| 欧美激情一区在线| 久久久久在线| 亚洲免费伊人电影在线观看av| 在线日本欧美| 国产欧美日韩在线 | 午夜免费电影一区在线观看| 亚洲电影免费在线观看| 欧美一区二区在线免费播放| 99热这里只有精品8| 伊人久久亚洲影院| 国产伦精品一区二区三区视频孕妇| 欧美电影免费观看| 久久精品一二三| 亚洲一区免费观看| 亚洲美女黄网| 亚洲国产裸拍裸体视频在线观看乱了| 久久精品视频99| 亚洲欧美一区二区激情| 国产精品99久久久久久有的能看| 在线成人亚洲| 精品不卡一区| 狠狠久久亚洲欧美| 狠狠狠色丁香婷婷综合久久五月 | 欧美精品在线看| 久久综合网色—综合色88| 欧美专区中文字幕| 欧美一区=区| 午夜激情综合网| 亚洲一区二区三区四区五区午夜| 日韩视频一区二区在线观看 | 日韩视频一区二区在线观看 | 欧美激情国产日韩| 欧美h视频在线| 欧美va日韩va| 欧美国产另类| 亚洲丰满在线| 亚洲国产成人av| 亚洲欧洲日韩综合二区| 亚洲人成在线观看| 日韩一二三区视频| 亚洲一区二区欧美| 亚洲欧美另类中文字幕| 亚洲男人的天堂在线aⅴ视频| 亚洲一区二区三区精品动漫| 亚洲免费在线| 久久精品国产成人| 美女成人午夜| 欧美日韩免费观看一区二区三区| 欧美日韩www| 国产精品嫩草影院一区二区| 国产麻豆综合| 永久555www成人免费| 亚洲国产91色在线| 中文日韩在线| 久久精品国产第一区二区三区最新章节| 久久精品99久久香蕉国产色戒 | 在线视频亚洲| 欧美一级二区| 男女精品网站| 99ri日韩精品视频| 午夜亚洲福利| 免费不卡中文字幕视频| 欧美色综合网| 国内精品久久久久久影视8| 亚洲黄色成人久久久| 亚洲一区二区三区高清| 久久久久久一区二区| 91久久久久久久久久久久久| 亚洲在线观看免费视频| 久久久精品tv| 欧美日韩一卡| 一区在线播放视频| 亚洲在线观看免费视频| 美女黄色成人网| 一区二区三区视频在线看| 久久久久久午夜| 国产精品久久久久久久午夜片 | 国产精品国码视频| 在线成人中文字幕| 欧美影院视频| 亚洲精品少妇网址| 久久综合狠狠综合久久激情| 欧美午夜性色大片在线观看|