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

隨筆-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>
            亚洲精品美女在线| 香蕉久久夜色精品国产| 亚洲精品少妇30p| 91久久中文| 亚洲精品美女久久久久| 亚洲视频狠狠| 久久成人精品视频| 美国十次成人| 亚洲欧洲一级| 亚洲欧美日韩国产综合精品二区 | 一区二区三区在线高清| 国产在线精品自拍| 亚洲免费高清| 久久gogo国模裸体人体| 欧美国产精品一区| 午夜视频在线观看一区二区三区| 久久亚洲电影| 国产午夜亚洲精品理论片色戒| 亚洲国产综合视频在线观看| 亚洲一区二区三区在线视频| 久久这里只精品最新地址| 亚洲精品无人区| 欧美 日韩 国产 一区| 国产日韩欧美电影在线观看| 亚洲视频在线二区| 亚洲激情六月丁香| 欧美黄在线观看| 亚洲激情国产| 国产免费亚洲高清| 在线视频你懂得一区| 亚洲国产精品热久久| 久久免费视频网| 国产精品视频99| 欧美亚洲日本网站| 午夜精品久久久久久久99樱桃| 国产精品蜜臀在线观看| 亚洲欧美日韩综合aⅴ视频| 在线亚洲免费| 国产伦精品一区二区三区照片91 | 亚洲一区二区三区四区五区黄 | 日韩写真在线| 91久久午夜| 国产精品久久久久久久9999| 亚洲性xxxx| 久久久国产精品亚洲一区 | 欧美有码视频| 噜噜噜久久亚洲精品国产品小说| 亚洲人成人一区二区在线观看| 99国产精品国产精品久久 | 亚洲欧美日韩精品久久| 黄色日韩精品| 一本大道久久a久久精品综合 | 久久亚洲精品一区| 国产精品99久久99久久久二8 | 免费观看欧美在线视频的网站| 亚洲大胆人体在线| 亚洲午夜未删减在线观看| 在线精品视频一区二区三四| 中文国产亚洲喷潮| 亚洲麻豆国产自偷在线| 女主播福利一区| 亚洲电影av在线| 亚洲高清成人| 欧美成人午夜免费视在线看片 | 亚洲激情综合| 亚洲国产欧美在线人成| 久久久一区二区| 免费看av成人| 在线观看亚洲视频啊啊啊啊| 羞羞色国产精品| 久久精品久久综合| 激情欧美一区二区三区| 校园春色国产精品| 久久综合九色综合久99| 亚洲电影下载| 欧美午夜精品久久久久久孕妇| 99精品国产一区二区青青牛奶 | 国产精品久久久91| 亚洲影视在线播放| 久久精品中文| 亚洲精品免费看| 欧美先锋影音| 久久久xxx| 一区二区免费在线播放| 亚洲欧美日韩一区二区在线| 亚洲欧美日韩一区二区三区在线| 国产精品夜色7777狼人| 久久国产视频网站| 亚洲理论在线观看| 久久婷婷影院| 亚洲天堂免费在线观看视频| 狠狠色狠狠色综合日日小说| 欧美激情精品| 精品成人国产在线观看男人呻吟| 欧美日韩国产区| 久久综合九色综合欧美狠狠| 在线一区亚洲| 亚洲黄一区二区| 欧美福利影院| 久久久福利视频| 亚洲伊人网站| 一区二区三区精品国产| 最新国产乱人伦偷精品免费网站| 国产毛片一区| 欧美午夜精品久久久久久浪潮| 久久五月天婷婷| 久久综合九色综合欧美狠狠| 午夜伦欧美伦电影理论片| 亚洲手机视频| 日韩视频在线免费| 亚洲麻豆av| 一区二区三区高清在线| 一区二区三区.www| 亚洲一区中文| 久久国产日韩| 欧美精品日韩综合在线| 欧美国产日韩一区二区三区| 国产精品免费一区二区三区观看| 亚洲一区二区黄| 亚洲视频久久| 亚洲国产三级网| 亚洲精品视频二区| 一区二区三区高清| 国产精品99久久久久久久久| 极品裸体白嫩激情啪啪国产精品| 激情欧美一区| 日韩天堂在线视频| 性色av一区二区三区| 久久蜜臀精品av| 亚洲国产精品久久人人爱蜜臀| 日韩亚洲在线| 欧美激情成人在线| 亚洲第一福利社区| 久久精品成人一区二区三区| 在线午夜精品自拍| 欧美黄色一级视频| 99精品国产在热久久| 亚洲精品久久久久中文字幕欢迎你| 亚洲精品美女久久7777777| 日韩视频在线永久播放| 亚洲一区二区成人| 香蕉国产精品偷在线观看不卡| 国产精品美女主播| 久久aⅴ国产紧身牛仔裤| 中日韩美女免费视频网址在线观看 | 国产亚洲精品一区二区| 亚洲一区二区三区中文字幕| 亚洲天堂av在线免费观看| 国产精品乱码一区二三区小蝌蚪 | 亚洲综合视频1区| 欧美色图麻豆| 亚洲综合色激情五月| 国产精品99久久久久久久久久久久| 老司机成人网| aa亚洲婷婷| 久久成人免费电影| 亚洲乱码国产乱码精品精可以看| 亚洲一区二区精品在线观看| 在线电影一区| 亚洲欧美三级伦理| 亚洲一区二区免费视频| 欧美母乳在线| 91久久亚洲| 国产日韩欧美三级| 久久久不卡网国产精品一区| 欧美一二三区在线观看| 国产在线欧美日韩| 亚洲国产成人高清精品| 国产精品腿扒开做爽爽爽挤奶网站| 中国亚洲黄色| 久久青草久久| 亚洲系列中文字幕| 麻豆精品网站| 久久精品视频一| 欧美日本韩国一区| 蜜桃伊人久久| 国产婷婷97碰碰久久人人蜜臀| 亚洲国产乱码最新视频| 国产欧美日韩综合精品二区| 亚洲高清在线观看一区| 国产一区二区三区在线观看免费视频 | 亚洲精品久久久久久久久久久久| 国产精品一卡二卡| 一个色综合av| 在线视频免费在线观看一区二区| 久久久久久电影| 久久日韩精品| 亚洲成人资源网| 久久精品中文| 免费日韩精品中文字幕视频在线| 国产欧美综合一区二区三区| 亚洲欧美日韩国产综合精品二区| 亚洲在线视频观看| 国产精品一区二区三区久久| 亚洲午夜一区| 久久狠狠亚洲综合| 亚洲国产精品久久久久久女王| 久久人人97超碰精品888| 欧美激情第8页| 亚洲无线观看|