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

隨筆-4  評論-40  文章-117  trackbacks-0

 

轉載

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

關于#和##

在C語言的宏中,#的功能是將其后面的宏參數進行字符串化操作(Stringfication),簡單說就是在對它所引用的宏變量通過替換后在其左右各加上一個雙引號。比如下面代碼中的宏:
#define WARN_IF(EXP)     \
     do{ if (EXP)     \
             fprintf(stderr, "Warning: " #EXP "\n"); }    \
     while(0)
那么實際使用中會出現下面所示的替換過程:
WARN_IF (divider == 0);
被替換為
do {
     if (divider == 0)
fprintf(stderr, "Warning" "divider == 0" "\n");
} while(0);
這樣每次divider(除數)為0的時候便會在標準錯誤流上輸出一個提示信息。

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

struct command
{
char * name;
void (*function) (void);
};
#define COMMAND(NAME) { NAME, NAME ## _command }
// 然后你就用一些預先定義好的命令來方便的初始化一個command結構的數組了:
struct command commands[] = {
COMMAND(quit),
COMMAND(help),
...
}
COMMAND宏在這里充當一個代碼生成器的作用,這樣可以在一定程度上減少代碼密度,間接地也可以減少不留心所造成的錯誤。我們還可以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;

關于...的使用

...在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一樣,變參必須作為參數表的最有一項出現。當上面的宏中我們只能提供第一個參數templt時,C標準要求我們必須寫成:
myprintf(templt,);
的形式。這時的替換過程為:
myprintf("Error!\n",);
替換為:
fprintf(stderr,"Error!\n",);
這是一個語法錯誤,不能正常編譯。這個問題一般有兩個解決方法。首先,GNU CPP提供的解決方法允許上面的宏調用寫成:
myprintf(templt);
而它將會被通過替換變成:
fprintf(stderr,"Error!\n",);
很明顯,這里仍然會產生編譯錯誤(非本例的某些情況下不會產生編譯錯誤)。除了這種方式外,c99和GNU CPP都支持下面的宏定義方式:
#define myprintf(templt, ...) fprintf(stderr,templt, ##__VAR_ARGS__)
這時,##這個連接符號充當的作用就是當__VAR_ARGS__為空的時候,消除前面的那個逗號。那么此時的翻譯過程如下:
myprintf(templt);
被轉化為:
fprintf(stderr,templt);
這樣如果templt合法,將不會產生編譯錯誤。 這里列出了一些宏使用中容易出錯的地方,以及合適的使用方式。

錯誤的嵌套-Misnesting

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

由操作符優先級引起的問題-Operator Precedence Problem

由于宏只是簡單的替換,宏的參數如果是復合結構,那么通過替換之后可能由于各個參數之間的操作符優先級高于單個參數內部各部分之間相互作用的操作符優先級,如果我們不用括號保護各個宏參數,可能會產生預想不到的情形。比如:
#define ceil_div(x, y) (x + y - 1) / y
那么
a = ceil_div( b & c, sizeof(int) );
將被轉化為:
a = ( b & c   + sizeof(int) - 1) / sizeof(int);
// 由于+/-的優先級高于&的優先級,那么上面式子等同于:
a = ( b & (c + sizeof(int) - 1)) / sizeof(int);
這顯然不是調用者的初衷。為了避免這種情況發生,應當多寫幾個括號:
#define ceil_div(x, y) (((x) + (y) - 1) / (y))

消除多余的分號-Semicolon Swallowing

通常情況下,為了使函數模樣的宏在表面上看起來像一個通常的C語言調用一樣,通常情況下我們在宏的后面加上一個分號,比如下面的帶參宏:
MY_MACRO(x);
但是如果是下面的情況:
#define MY_MACRO(x) { \
/* line 1 */ \
/* line 2 */ \
/* line 3 */ }
//...
if (condition())
MY_MACRO(a);
else
{...}
這樣會由于多出的那個分號產生編譯錯誤。為了避免這種情況出現同時保持MY_MACRO(x);的這種寫法,我們需要把宏定義為這種形式:
#define MY_MACRO(x) do {
/* line 1 */ \
/* line 2 */ \
/* line 3 */ } while(0)
這樣只要保證總是使用分號,就不會有任何問題。

Duplication of Side Effects

這里的Side Effect是指宏在展開的時候對其參數可能進行多次Evaluation(也就是取值),但是如果這個宏參數是一個函數,那么就有可能被調用多次從而達到不一致的結果,甚至會發生更嚴重的錯誤。比如:
#define min(X,Y) ((X) > (Y) ? (Y) : (X))
//...
c = min(a,foo(b));
這時foo()函數就被調用了兩次。為了解決這個潛在的問題,我們應當這樣寫min(X,Y)這個宏:
#define min(X,Y) ({ \
typeof (X) x_ = (X); \
typeof (Y) y_ = (Y); \
(x_ < y_) ? x_ : y_; })
({...})的作用是將內部的幾條語句中最后一條的值返回,它也允許在內部聲明變量(因為它通過大括號組成了一個局部Scope)。
posted on 2007-11-22 16:39 李陽 閱讀(211) 評論(0)  編輯 收藏 引用 所屬分類: C++
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            午夜精品福利一区二区三区av| 亚洲视频在线观看网站| 免费观看日韩av| 久久综合九九| 欧美va天堂va视频va在线| 久热精品视频在线观看| 欧美jizz19性欧美| 欧美日韩国产二区| 国产精品久久久久久久9999 | 亚洲每日在线| 一道本一区二区| 香港久久久电影| 久久欧美中文字幕| 亚洲国产精品精华液网站| 亚洲精品无人区| 亚洲影院免费观看| 亚洲欧美国产77777| 一区视频在线| 欧美精品一区二区三区蜜桃| 欧美区日韩区| 国产一区二区高清不卡| 亚洲国产成人91精品| 亚洲九九爱视频| 亚洲一区二区三区四区五区黄| 久久国内精品视频| 最近中文字幕日韩精品 | 亚洲高清在线精品| 在线视频日本亚洲性| 久久精品亚洲精品国产欧美kt∨| 欧美久久婷婷综合色| 国产亚洲成精品久久| 日韩天堂av| 麻豆国产精品va在线观看不卡| 亚洲免费av电影| 免费成人网www| 国产欧美一区视频| 一区二区三区精品国产| 久久综合网色—综合色88| 9l视频自拍蝌蚪9l视频成人| 久久婷婷成人综合色| 国产精品自在在线| 亚洲视频香蕉人妖| 亚洲人成在线播放| 久久免费视频这里只有精品| 国产精品二区在线观看| 日韩小视频在线观看| 亚洲电影免费观看高清完整版在线 | 国产精品久久久久aaaa| 最新中文字幕亚洲| 欧美成人r级一区二区三区| 亚洲尤物视频网| 欧美网站在线| 一本色道久久综合亚洲精品按摩| 另类天堂av| 久久国产精品99国产精| 国产日本欧美一区二区| 欧美一区二区精品| 亚洲一区二区少妇| 国产精品视频yy9099| 午夜精品影院在线观看| 亚洲综合首页| 国产精品日韩欧美| 久久久999国产| 欧美一区精品| 好吊视频一区二区三区四区| 久久久精彩视频| 久久久欧美一区二区| 亚洲成色777777女色窝| 亚洲福利国产| 久热这里只精品99re8久| 久久久av毛片精品| 国产精品xxxav免费视频| 亚洲午夜精品一区二区三区他趣| 亚洲精品一区二区三区av| 欧美区二区三区| 亚洲永久免费| 午夜欧美理论片| 激情成人在线视频| 亚洲国产婷婷| 欧美丝袜一区二区| 久久精品亚洲| 免费在线观看精品| 中文国产一区| 亚洲欧美日韩国产| 亚洲国产裸拍裸体视频在线观看乱了 | 国产婷婷色综合av蜜臀av| 久久婷婷人人澡人人喊人人爽| 久久久久久亚洲精品杨幂换脸| 91久久中文| 亚洲综合色在线| 亚洲丰满少妇videoshd| 亚洲激情欧美激情| 国产日韩欧美视频| 欧美激情网友自拍| 国产精品丝袜xxxxxxx| 米奇777在线欧美播放| 欧美日韩免费在线观看| 久久米奇亚洲| 欧美日韩国产综合网| 欧美专区在线观看一区| 欧美国产精品| 久久国产精品一区二区| 欧美日本一区二区视频在线观看| 性久久久久久久| 欧美国产视频一区二区| 久久久天天操| 国产精品麻豆va在线播放| 欧美成人精品在线| 国产伦精品一区二区三区四区免费 | 欧美日韩在线免费| 欧美va天堂在线| 国产精品乱码一区二区三区| 暖暖成人免费视频| 国产精品亚洲综合| 亚洲欧洲偷拍精品| 影音先锋成人资源站| 亚洲天堂网站在线观看视频| 亚洲欧洲日本mm| 久久夜色精品国产亚洲aⅴ| 欧美一区二区三区视频在线| 欧美日韩国产一区精品一区| 免费一级欧美在线大片| 99成人精品| 99综合电影在线视频| 欧美精品入口| 亚洲欧美日韩在线高清直播| 亚洲影院在线观看| 亚洲国产成人av好男人在线观看| 亚洲国产综合在线看不卡| 国产精品高潮呻吟久久av黑人| 羞羞视频在线观看欧美| 欧美成黄导航| 欧美成人黄色小视频| 国产精品高清在线| 亚洲欧洲一区二区三区| 激情另类综合| 午夜在线一区| 亚洲综合视频一区| 欧美日韩在线看| 亚洲精品中文字幕在线观看| 在线欧美视频| 久久久.com| 久久亚洲私人国产精品va| 国产日韩在线不卡| 午夜久久影院| 久久精品国产第一区二区三区| 国产精品久久久久7777婷婷| 亚洲国产裸拍裸体视频在线观看乱了| 狠狠久久婷婷| 老司机久久99久久精品播放免费| 久久这里只有精品视频首页| 伊人精品视频| 免费一区视频| 亚洲国产另类精品专区| 亚洲人成免费| 欧美日韩精品久久| 一本色道**综合亚洲精品蜜桃冫| 在线视频欧美一区| 国产精品久久久久av免费| 亚洲午夜精品久久久久久浪潮| 亚洲性视频h| 国产毛片久久| 久久精品国产亚洲aⅴ| 免费成人黄色av| 亚洲精品久久久久久久久| 欧美日韩精品一区二区在线播放| 一本色道久久加勒比88综合| 亚洲欧美日本日韩| 国内精品久久久久久久影视麻豆 | 亚洲黄页一区| 一区二区三区四区五区精品视频| 欧美日韩在线不卡| 午夜精品久久久久久久| 免费不卡亚洲欧美| 在线中文字幕日韩| 国产夜色精品一区二区av| 久久综合国产精品| 一区二区三区久久| 猛男gaygay欧美视频| 中文亚洲视频在线| av成人福利| 久久不射电影网| 亚洲毛片播放| 国内偷自视频区视频综合| 欧美精品在线播放| 久久国产精品电影| 夜夜嗨av一区二区三区四季av| 久久久久免费| 亚洲亚洲精品三区日韩精品在线视频| 国产亚洲亚洲| 欧美午夜一区二区福利视频| 久久夜色精品国产| 亚洲欧美大片| 日韩亚洲欧美一区| 欧美国产1区2区| 久久精品日产第一区二区| 亚洲一区bb| 一本色道久久综合| 亚洲激情av| 在线精品亚洲|