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

elva

C語言宏定義使用技巧

寫好C語言,漂亮的宏定義很重要,使用宏定義可以防止出錯,提高可移植性,可讀性,方便性 等等。下面列舉一些成熟軟件中常用得宏定義。。。。。。
1,防止一個頭文件被重復包含

#ifndef COMDEF_H
#define COMDEF_H
//頭文件內容
#endif
2,重新定義一些類型,防止由于各種平臺和編譯器的不同,而產生的類型字節數差異,方便移植。
typedef unsigned char boolean; /* Boolean value type. */
typedef unsigned long int uint32; /* Unsigned 32 bit value */
typedef unsigned short uint16; /* Unsigned 16 bit value */
typedef unsigned char uint8; /* Unsigned 8 bit value */
typedef signed long int int32; /* Signed 32 bit value */
typedef signed short int16; /* Signed 16 bit value */
typedef signed char int8; /* Signed 8 bit value */
//下面的不建議使用
typedef unsigned char byte; /* Unsigned 8 bit value type. */
typedef unsigned short word; /* Unsinged 16 bit value type. */
typedef unsigned long dword; /* Unsigned 32 bit value type. */
typedef unsigned char uint1; /* Unsigned 8 bit value type. */
typedef unsigned short uint2; /* Unsigned 16 bit value type. */
typedef unsigned long uint4; /* Unsigned 32 bit value type. */
typedef signed char int1; /* Signed 8 bit value type. */
typedef signed short int2; /* Signed 16 bit value type. */
typedef long int int4; /* Signed 32 bit value type. */
typedef signed long sint31; /* Signed 32 bit value */
typedef signed short sint15; /* Signed 16 bit value */
typedef signed char sint7; /* Signed 8 bit value */
3,得到指定地址上的一個字節或字
#define MEM_B( x ) ( *( (byte *) (x) ) )
#define MEM_W( x ) ( *( (word *) (x) ) )
4,求最大值和最小值
#define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )
#define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )
5,得到一個field在結構體(struct)中的偏移量
#define FPOS( type, field ) \
/*lint -e545 */ ( (dword) &(( type *) 0)-> field ) /*lint +e545 */
6,得到一個結構體中field所占用的字節數
#define FSIZ( type, field ) sizeof( ((type *) 0)->field )
7,按照LSB格式把兩個字節轉化為一個Word
#define FLIPW( ray ) ( (((word) (ray)[0]) * 256) + (ray)[1] )
8,按照LSB格式把一個Word轉化為兩個字節
#define FLOPW( ray, val ) \
(ray)[0] = ((val) / 256); \
(ray)[1] = ((val) & 0xFF)
9,得到一個變量的地址(word寬度)
#define B_PTR( var ) ( (byte *) (void *) &(var) )
#define W_PTR( var ) ( (word *) (void *) &(var) )
10,得到一個字的高位和低位字節
#define WORD_LO(***) ((byte) ((word)(***) & 255))
#define WORD_HI(***) ((byte) ((word)(***) >> 8))
11,返回一個比X大的最接近的8的倍數
#define RND8( x ) ((((x) + 7) / 8 ) * 8 )
12,將一個字母轉換為大寫
#define UPCASE( c ) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )
13,判斷字符是不是10進值的數字
#define DECCHK( c ) ((c) >= '0' && (c) <= '9')
14,判斷字符是不是16進值的數字
#define HEXCHK( c ) ( ((c) >= '0' && (c) <= '9') ||\
((c) >= 'A' && (c) <= 'F') ||\
((c) >= 'a' && (c) <= 'f') )
15,防止溢出的一個方法
#define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))
16,返回數組元素的個數
#define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )
17,返回一個無符號數n尾的值MOD_BY_POWER_OF_TWO(X,n)=X%(2^n)
#define MOD_BY_POWER_OF_TWO( val, mod_by ) \
( (dword)(val) & (dword)((mod_by)-1) )
18,對于IO空間映射在存儲空間的結構,輸入輸出處理
#define inp(port) (*((volatile byte *) (port)))
#define inpw(port) (*((volatile word *) (port)))
#define inpdw(port) (*((volatile dword *)(port)))
#define outp(port, val) (*((volatile byte *) (port)) = ((byte) (val)))
#define outpw(port, val) (*((volatile word *) (port)) = ((word) (val)))
#define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))
[2005-9-9添加]
19,使用一些宏跟蹤調試
A N S I標準說明了五個預定義的宏名。它們是:
_ L I N E _
_ F I L E _
_ D A T E _
_ T I M E _
_ S T D C _
如果編譯不是標準的,則可能僅支持以上宏名中的幾個,或根本不支持。記住編譯程序
也許還提供其它預定義的宏名。
_ L I N E __ F I L E _宏指令在有關# l i n e的部分中已討論,這里討論其余的宏名。
_ D AT E _宏指令含有形式為月//年的串,表示源文件被翻譯到代碼時的日期。
源代碼翻譯到目標代碼的時間作為串包含在_ T I M E _中。串形式為時:分:秒。
如果實現是標準的,則宏_ S T D C _含有十進制常量1。如果它含有任何其它數,則實現是
非標準的。
可以定義宏,例如:
當定義了_DEBUG,輸出數據信息和所在文件所在行
#ifdef _DEBUG
#define DEBUGMSG(msg,date) printf(msg);printf(“%d%d%d”,date,_LINE_,_FILE_)
#else
#define DEBUGMSG(msg,date)
#endif
20,宏定義防止使用是錯誤
用小括號包含。
例如:#define ADD(a,b) a+b
do{}while(0)語句包含多語句防止錯誤
例如:#difne DO(a,b) a+b;\
a++;
應用時:if(.)
DO(a,b); //產生錯誤
else


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 2008-08-11 15:13 葉子 閱讀(2624) 評論(0)  編輯 收藏 引用 所屬分類: C\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一区二区三区中文字幕| 亚洲青色在线| 西西裸体人体做爰大胆久久久| 久久国产福利| 欧美激情在线有限公司| 亚洲系列中文字幕| 久久久久综合网| 欧美噜噜久久久xxx| 国产手机视频精品| 亚洲国产精品视频一区| 亚洲欧美精品| 久久米奇亚洲| 亚洲人成在线影院| 亚洲欧美国产毛片在线| 久久久久久久性| 欧美激情视频一区二区三区免费 | 性色av一区二区怡红| 欧美大片免费观看在线观看网站推荐| 欧美日韩另类视频| 亚洲国产va精品久久久不卡综合| 亚洲欧美日本国产专区一区| 欧美大片在线观看一区| 国产精品久久久久久久久搜平片| av成人天堂| 欧美一区二区三区免费观看| 欧美日本一区二区高清播放视频| 国产欧美日韩精品专区| 99精品视频免费观看视频| 美玉足脚交一区二区三区图片| 一区二区久久久久久| 欧美成人久久| 在线电影一区| 久久亚洲视频| 亚洲视频999| 欧美剧在线观看| 亚洲国产成人av| 久久婷婷成人综合色| 亚洲视频第一页| 欧美日韩一区在线播放| 亚洲国产成人久久| 久久久久久久欧美精品| 亚洲巨乳在线| 欧美激情视频免费观看| 久久深夜福利| 亚洲第一网站| 欧美黑人多人双交| 久久精品国产99国产精品澳门 | 亚洲性夜色噜噜噜7777| 欧美日本国产在线| 亚洲一区二区伦理| 亚洲视频导航| 国产日韩欧美在线播放不卡| 久久av在线| 久久精品99无色码中文字幕| 国内精品久久久| 国产区亚洲区欧美区| 久久国产精品网站| 欧美在线观看视频在线| 影音先锋久久| 亚洲国产一区二区三区青草影视| 牛夜精品久久久久久久99黑人| 亚洲第一网站免费视频| 亚洲电影第三页| 欧美日韩另类在线| 亚洲一级在线| 欧美一级视频精品观看| 国产精品欧美日韩一区| 午夜亚洲性色福利视频| 午夜天堂精品久久久久| 国内成人精品2018免费看| 亚洲第一页中文字幕| 欧美日韩系列| 亚洲欧美电影在线观看| 久久精品卡一| 亚洲精品日韩在线观看| 中文在线资源观看网站视频免费不卡| 国产精品magnet| 久久精品国产综合| 亚洲日本视频| 一本到高清视频免费精品| 欧美视频日韩视频| 亚洲精选一区| 国产亚洲福利一区| 久久久青草婷婷精品综合日韩| 久久久久久999| 一区二区三区四区精品| 一区二区国产精品| 国语精品中文字幕| 亚洲免费成人av| 国内视频一区| 在线视频欧美一区| 黄色成人免费观看| 亚洲激情视频在线播放| 欧美体内she精视频| 蜜臀va亚洲va欧美va天堂| 国产精品v欧美精品∨日韩| 久久乐国产精品| 国产精品免费视频xxxx| 91久久在线观看| 在线观看不卡av| 亚洲欧美综合| 在线亚洲欧美| 欧美激情影院| 欧美黄色网络| 黄页网站一区| 欧美一区二区三区四区视频| 中文在线一区| 欧美激情中文字幕乱码免费| 免费欧美网站| 国产综合av| 欧美一区二粉嫩精品国产一线天| 亚洲一区二区三区午夜| 欧美美女bbbb| 亚洲激情电影在线| 亚洲人成网站在线观看播放| 久久这里有精品15一区二区三区| 久久精品在线播放| 国产亚洲精品久久久久婷婷瑜伽| 亚洲精品中文字幕在线| 亚洲大片一区二区三区| 久久精品国产久精国产一老狼 | 欧美日韩美女| 亚洲国产成人精品视频| 国模吧视频一区| 久久黄色级2电影| 欧美在线视频导航| 国产乱码精品| 欧美一区二粉嫩精品国产一线天| 午夜精品国产| 国产精品日韩精品欧美精品| 亚洲综合三区| 欧美在线日韩在线| 有码中文亚洲精品| 久久女同互慰一区二区三区| 久久久水蜜桃| 亚洲国产精品va在线看黑人| 欧美韩日一区二区| 日韩视频在线一区二区| 亚洲欧美日韩精品久久久| 国产美女一区二区| 久久综合影视| 亚洲成色精品| av成人老司机| 国产精品v欧美精品v日韩| 亚洲一区区二区| 久久狠狠一本精品综合网| 欧美一区二区三区四区在线观看地址| 国产主播一区二区三区| 久久蜜桃av一区精品变态类天堂| 久久国产视频网站| 亚洲国产精品久久久久秋霞影院 | 亚洲欧美日韩区| 久久青草福利网站| 99v久久综合狠狠综合久久| 欧美精品色综合| 亚洲欧美日韩视频二区| 亚洲国产精品成人一区二区| 亚洲欧美三级伦理| 亚洲国产免费| 国产目拍亚洲精品99久久精品| 久久伊人免费视频| 中国成人亚色综合网站| 老司机午夜精品视频在线观看| 99国产麻豆精品| 国模大胆一区二区三区| 欧美午夜精品| 免费观看亚洲视频大全| 亚洲欧洲av一区二区| 亚洲人成啪啪网站| 久久综合999| 小嫩嫩精品导航| 日韩一区二区电影网| 狠狠色香婷婷久久亚洲精品| 欧美午夜电影在线| 欧美国产欧美亚洲国产日韩mv天天看完整 | 久久先锋影音| 亚洲天堂av在线免费观看| 亚洲成人资源| 欧美freesex8一10精品| 久久精品国产免费观看| 亚洲午夜激情网页| 亚洲伦理在线免费看| 一区福利视频| 黄色精品在线看|