blackrain 发表于 2006-3-1 14:06:50

C语言常用宏定义技巧

C语言宏定义技巧(常用宏定义)



写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性 等等。下面列举一些成熟软件中常用得宏定义。。。。。。







1,防止一个头文件被重复包含



#ifndef COMDEF_H



#define COMDEF_H



//头文件内容



#endif



2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植。



typedefunsigned char      boolean;   /* Boolean value type. */







typedefunsigned long intuint32;      /* Unsigned 32 bit value */



typedefunsigned short   uint16;      /* Unsigned 16 bit value */



typedefunsigned char      uint8;       /* Unsigned 8bit value */







typedefsigned long int    int32;       /* Signed 32 bit value */



typedefsigned short       int16;       /* Signed 16 bit value */



typedefsigned char      int8;      /* Signed 8bit value */











//下面的不建议使用



typedefunsigned char   byte;         /* Unsigned 8bit value type. */



typedefunsigned short    word;         /* Unsinged 16 bit value type. */



typedefunsigned long   dword;      /* Unsigned 32 bit value type. */







typedefunsigned char   uint1;      /* Unsigned 8bit value type. */



typedefunsigned short    uint2;      /* Unsigned 16 bit value type. */



typedefunsigned long   uint4;      /* Unsigned 32 bit value type. */







typedefsigned char       int1;         /* Signed 8bit value type. */



typedefsigned short      int2;         /* Signed 16 bit value type. */



typedeflong int          int4;         /* Signed 32 bit value type. */







typedefsigned long       sint31;       /* Signed 32 bit value */



typedefsigned short      sint15;       /* Signed 16 bit value */



typedefsigned char       sint7;      /* Signed 8bit value */







3,得到指定地址上的一个字节或字



#defineMEM_B( x )( *( (byte *) (x) ) )



#defineMEM_W( x )( *( (word *) (x) ) )



4,求最大值和最小值



   #defineMAX( x, y ) ( ((x) > (y)) ? (x) : (y) )



   #defineMIN( 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



#defineFLIPW( ray ) ( (((word) (ray)) * 256) + (ray) )



8,按照LSB格式把一个Word转化为两个字节



#defineFLOPW( ray, val ) \



(ray) = ((val) / 256); \



(ray) = ((val) & 0xFF)



9,得到一个变量的地址(word宽度)



#defineB_PTR( var )( (byte *) (void *) &(var) )



#defineW_PTR( var )( (word *) (void *) &(var) )



10,得到一个字的高位和低位字节



#defineWORD_LO(xxx)((byte) ((word)(xxx) & 255))



#defineWORD_HI(xxx)((byte) ((word)(xxx) >> 8))



11,返回一个比X大的最接近的8的倍数



#define RND8( x )       ((((x) + 7) / 8 ) * 8 )



12,将一个字母转换为大写



#defineUPCASE( c ) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )



13,判断字符是不是10进值的数字



#defineDECCHK( c ) ((c) >= '0' && (c) <= '9')



14,判断字符是不是16进值的数字



#defineHEXCHK( c ) ( ((c) >= '0' && (c) <= '9') ||\



                     ((c) >= 'A' && (c) <= 'F') ||\



((c) >= 'a' && (c) <= 'f') )



15,防止溢出的一个方法



#defineINC_SAT( val )(val = ((val)+1 > (val)) ? (val)+1 : (val))



16,返回数组元素的个数



#defineARR_SIZE( a )( sizeof( (a) ) / sizeof( (a) ) )



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







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



      



解决方法: #difne DO(a,b) do{a+b;\



                   a++;}while(0)

kinsey 发表于 2006-3-1 15:16:01

帮你顶起来。

jackrich 发表于 2006-3-1 16:19:29

很好的学习材料!!! 谢谢

blackrain 发表于 2006-3-1 16:32:32

 宏中"#"和"##"的用法

一、一般用法

我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起.

用法:

#include<cstdio>

#include<climits>

using namespace std;



#define STR(s)   #s

#define CONS(a,b)int(a##e##b)



int main()

{

    printf(STR(vck));         // 输出字符串"vck"

    printf("%d
", CONS(2,3));// 2e3 输出:2000

    return 0;

}



二、当宏参数是另一个宏的时候

需要注意的是凡宏定义里有用'#'或'##'的地方宏参数是不会再展开.



1, 非'#'和'##'的情况

#define TOW      (2)

#define MUL(a,b) (a*b)



printf("%d*%d=%d
", TOW, TOW, MUL(TOW,TOW));

这行的宏会被展开为:

printf("%d*%d=%d
", (2), (2), ((2)*(2)));

MUL里的参数TOW会被展开为(2).



2, 当有'#'或'##'的时候

#define A          (2)

#define STR(s)   #s

#define CONS(a,b)int(a##e##b)



printf("int max: %s
",STR(INT_MAX));    // INT_MAX #include<climits>

这行会被展开为:

printf("int max: %s
", "INT_MAX");



printf("%s
", CONS(A, A));               // compile error

这一行则是:

printf("%s
", int(AeA));



INT_MAX和A都不会再被展开, 然而解决这个问题的方法很简单. 加多一层中间转换宏.

加这层宏的用意是把所有宏的参数在这层里全部展开, 那么在转换宏里的那一个宏(_STR)就能得到正确的宏参数.



#define A         (2)

#define _STR(s)   #s

#define STR(s)      _STR(s)          // 转换宏

#define _CONS(a,b)int(a##e##b)

#define CONS(a,b)   _CONS(a,b)       // 转换宏



printf("int max: %s
", STR(INT_MAX));          // INT_MAX,int型的最大值,为一个变量 #include<climits>

输出为: int max: 0x7fffffff

STR(INT_MAX) -->_STR(0x7fffffff) 然后再转换成字符串;



printf("%d
", CONS(A, A));

输出为:200

CONS(A, A)-->_CONS((2), (2))--> int((2)e(2))



三、'#'和'##'的一些应用特例

1、合并匿名变量名

#define___ANONYMOUS1(type, var, line)typevar##line

#define__ANONYMOUS0(type, line)___ANONYMOUS1(type, _anonymous, line)

#defineANONYMOUS(type)__ANONYMOUS0(type, __LINE__)

例:ANONYMOUS(static int);即: static int _anonymous70;70表示该行行号;

第一层:ANONYMOUS(static int);-->__ANONYMOUS0(static int, __LINE__);

第二层:                        -->___ANONYMOUS1(static int, _anonymous, 70);

第三层:                        -->static int_anonymous70;

即每次只能解开当前层的宏,所以__LINE__在第二层才能被解开;



2、填充结构

#defineFILL(a)   {a, #a}



enum IDD{OPEN, CLOSE};

typedef struct MSG{

IDD id;

const char * msg;

}MSG;



MSG _msg[] = {FILL(OPEN), FILL(CLOSE)};

相当于:

MSG _msg[] = {{OPEN, "OPEN"},

            {CLOSE, "CLOSE"}};



3、记录文件名

#define_GET_FILE_NAME(f)   #f

#defineGET_FILE_NAME(f)    _GET_FILE_NAME(f)

static charFILE_NAME[] = GET_FILE_NAME(__FILE__);



4、得到一个数值类型所对应的字符串缓冲大小

#define_TYPE_BUF_SIZE(type)sizeof #type

#defineTYPE_BUF_SIZE(type)   _TYPE_BUF_SIZE(type)

charbuf;

   -->charbuf;

   -->charbuf;

这里相当于:

charbuf;

zheng8648 发表于 2006-3-1 20:10:25

不错嘛.

avrboy 发表于 2006-3-1 20:59:32

愛生活, 愛頂你!!

leeber 发表于 2006-3-2 16:18:12

收藏,仔细看看!

zhouheeng 发表于 2006-3-3 16:29:06

收藏待仔细看

coole 发表于 2006-3-3 19:48:35

好贴!顶!

9810956 发表于 2006-3-3 20:39:23

我顶./emotion/em210.gif

xecho 发表于 2006-3-4 15:03:57

./emotion/em109.gif楼主辛苦了。

编程就得有个好习惯。

alexant 发表于 2006-3-4 18:15:49

多谢楼主的精彩总结!

sea_19821 发表于 2006-3-4 18:34:44

好!

mycat168 发表于 2006-3-5 10:36:17

谢谢了

dm_dm 发表于 2006-3-5 15:49:01

哦开!

hncsxzj 发表于 2006-3-5 17:15:06

收藏,仔细看看! 谢了

lvyi913 发表于 2006-4-1 16:02:17

自相矛盾了 ,不介意用byte,而在后面的定义中自己却用了。呵呵,不好意思,有点叫真儿了。呵呵

psbhero 发表于 2006-4-6 12:32:20

谢谢

Gorgon_Meducer 发表于 2006-4-6 18:46:31

补充一点:

如果需要包含连续的代码请使用如下的模式,例如:

# define DoSomething    do{code1;code2;code3……}while(0)



这样做好处多多哦,慢慢体会吧——其实我也没有体会到,不过在Linux代码中经常看到。
-----此内容被Gorgon Meducer于2006-04-06,18:47:00编辑过

dzk0620 发表于 2006-4-12 13:47:09

好东西!!

energycf 发表于 2006-4-12 15:46:13

收获蛮大的~支持你

lanxieyu 发表于 2006-4-13 08:23:21

好东西,顶起来!!

多谢楼主,收获很大,近来一直在摆弄C,也初知宏定义的作用,但用起来却谈不上什么技巧,看了楼主的说明,明白了不少!!

zhangtomcom 发表于 2006-4-14 00:08:06

说的清楚明白,多谢!

thomas_top 发表于 2006-6-14 11:22:14

不错,再次顶!!

ghost2 发表于 2006-6-14 11:28:11

好文,好人!

liang4854 发表于 2006-7-19 16:44:12

不是很懂哦,但是看完必顶啊 。

CN.Cn 发表于 2006-7-19 16:57:07

统一25楼

shaozh 发表于 2006-7-19 21:54:10

好东西,顶!

SW7005 发表于 2006-7-20 12:25:07

多谢楼主

xiaoache 发表于 2006-7-20 17:14:43

楼主劳苦功高

xiaobao601 发表于 2006-7-20 20:16:42

多谢多谢!

楼主辛苦了。

q251163748 发表于 2006-7-21 13:19:02

我顶我顶

lxwm1983 发表于 2006-7-21 14:45:50

抓紧时间学习

bilijohn 发表于 2006-9-1 15:41:12

平时都是用汇编,正在努力转向C,多谢楼主提供这样好的资料(C学的烂啊,大部分东东的好处还没有看出来,呵呵~继续努力)

hhrfjz 发表于 2006-9-1 20:28:13

顶!

suzzy_2006 发表于 2006-9-1 21:21:49

多谢楼主!感激涕零

armoksb1 发表于 2006-9-2 06:53:47

谢谢!

wano 发表于 2006-9-2 08:10:44

flylive 发表于 2006-9-2 12:11:50

xiao5 发表于 2006-10-26 09:46:32

好东西

多谢楼主

hanlin 发表于 2006-11-26 00:26:33

好东西,收下了.

aini 发表于 2006-11-26 13:06:28

我要说宏不好,该用inline为主了的话,相信有很多人会不同意的啊

kite2006 发表于 2006-11-27 09:02:13

好东西,谢谢

shaozh 发表于 2006-11-27 09:16:47

好!好!好!

zhshp515 发表于 2006-11-27 11:20:11

好资料,认真学习~~

inr999 发表于 2007-1-6 14:57:25

虽然没有全看懂,不过也受益.多谢!

li3081 发表于 2007-2-27 13:36:47

好东西,顶!谢谢!

mcszhou 发表于 2007-7-1 15:18:44

顶 顶

Tim_yao 发表于 2007-7-1 16:26:22

不错

真是个好东西!

crrr 发表于 2007-7-1 19:51:52

很不错的学习材料

lzy4072 发表于 2007-7-2 10:26:30

顶!

dworld 发表于 2007-8-25 19:31:50

谢了,刚好遇到了#和##不能展开宏的问题。

laoma 发表于 2007-8-25 21:02:35

#define IO_DIR_PORT_PIN(port, pin, dir)\

   do {                                  \

      if (dir == IO_OUT)               \

         P##port##DIR |= (0x01<<(pin));\

      else                               \

         P##port##DIR &= ~(0x01<<(pin)); \

   }while(0)



刚学会的,谢谢

kennyhehe 发表于 2007-9-11 13:56:14

下载回去慢慢看~~

blxl 发表于 2007-9-11 15:13:24

7,按照LSB格式把两个字节转化为一个Word

#defineFLIPW( ray ) ( (((word) (ray)) * 256) + (ray) )

8,按照LSB格式把一个Word转化为两个字节

#defineFLOPW( ray, val ) \

(ray) = ((val) / 256); \

(ray) = ((val) & 0xFF)


用移位是不是更好?

billa 发表于 2007-9-11 16:37:10

顶一下

hecb999 发表于 2007-9-11 19:48:27

顶,好东东

feng200808 发表于 2007-9-12 10:56:15

不错,收藏了

Forever 发表于 2007-9-12 12:57:55

好东西!

bloodyrain 发表于 2007-9-12 14:41:55

谢谢楼主,   感觉很经典, 但是不是12分明白, 要是再多有点注释就更好了。


小小菜鸟, 大家多多帮助。

mowin 发表于 2007-9-13 12:03:39

收下了,谢谢,学习中

ediy007 发表于 2007-9-13 14:12:06

楼主辛苦了,学习中。

erhui_cn 发表于 2007-10-12 10:38:03

偶用的是uchar
uint
偶觉得这样用的人还是用的.不知上面为何没有...

morris 发表于 2007-10-12 10:59:36

好像還欠了 X-MACRO 的用法未有介紹。(Example quoted from Wiki)

X-Macros
One little-known usage-pattern of the C preprocessor is known as "X-Macros". X-Macros are the practice of using the #include directive multiple times on the same source header file, each time in a different environment of defined macros.

File: commands.def

COMMAND(ADD, "Addition command")
COMMAND(SUB, "Subtraction command")
COMMAND(XOR, "Exclusive-or command")
enum command_indices {
#define COMMAND(name, description)            COMMAND_##name ,
#include "commands.def"
#undef COMMAND
    COMMAND_COUNT /* The number of existing commands */
};

char *command_descriptions[] = {
#define COMMAND(name, description)            description ,
#include "commands.def"
#undef COMMAND
    NULL
};

result_t handler_ADD (state_t *)
{
/* code for ADD here */
}

result_t handler_SUB (state_t *)
{
/* code for SUB here */
}

result_t handler_XOR (state_t *)
{
/* code for XOR here */
}

typedef result_t (*command_handler_t)(state_t *);

command_handler_t command_handlers[] = {
#define COMMAND(name, description)            &handler_##name ,
#include "commands.def"
#undef COMMAND
    NULL
};

himalayan 发表于 2007-10-12 11:24:44

有些懂,有些不懂,慢慢学!谢谢!

chengjia535 发表于 2007-10-12 14:02:19

再顶

wxg_icer 发表于 2007-12-19 14:41:03

very good

hchkfh 发表于 2007-12-19 17:05:07

能不能用宏定义根据公式做一个存在程序区的数据表?

Merlunter 发表于 2007-12-20 13:27:15

haso2007 发表于 2007-12-20 21:48:17

收藏先,再慢慢学。
好的习惯是成功的开始

canking 发表于 2007-12-21 09:09:38

好东西,我顶啊

xyang18 发表于 2007-12-21 09:29:53

好东西,谢谢楼主了

lin28 发表于 2007-12-21 11:21:23

ding

sunke9 发表于 2007-12-21 14:59:08

收下了,谢谢,学习中

sgyyj 发表于 2007-12-23 12:08:48

顶!

hb8421 发表于 2007-12-28 14:35:01

好东西,顶起来!

zhao_123456 发表于 2008-1-15 11:47:47

myhome 发表于 2008-1-15 12:06:19

谢谢LZ!!!

guangdingli 发表于 2008-1-15 15:11:11

bu cuo!!!!!!!!

pang975027 发表于 2008-1-15 15:16:16

ding!!!学习了

HZZCL 发表于 2008-1-15 15:17:26

ding

mega128 发表于 2008-1-15 22:40:18

记号

mega128 发表于 2008-1-15 22:40:20

记号

maskiss 发表于 2008-1-25 16:22:43

打个烙印先,哪天要用就来查醒

525133174 发表于 2008-1-25 19:25:36

很有用

20065118 发表于 2008-1-25 21:07:08

可以啊~难得找到这样的文章~~~顶~~~

20065118 发表于 2008-1-25 21:09:34

再来顶一次~~

hjhwsk 发表于 2008-1-25 21:13:42

我顶

lj_3915 发表于 2008-1-26 10:45:24

收藏!!!!!!!!!1

asktutu 发表于 2008-1-26 15:12:09

顶起,顶起,不错。

lbk301 发表于 2008-1-26 15:31:18

楼主辛苦了。

lemonp 发表于 2008-4-3 13:52:02

好多还没用过,谢谢!

sciencehero 发表于 2008-4-3 13:54:07

记录!

gao2006good 发表于 2008-4-3 14:37:24

谢谢了

yzlyear 发表于 2008-4-3 14:47:46

teltium 发表于 2008-4-3 15:07:17

爱生活,爱阿莫

jmpxwh 发表于 2008-4-3 15:45:48

留个脚印!收下!

hlwjx 发表于 2008-4-3 16:40:10

收下了

bjj9217 发表于 2008-4-3 18:54:14

学习了

zhuzi1441 发表于 2008-4-4 15:12:04

不顶不行呀
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: C语言常用宏定义技巧