搜索
bottom↓
回复: 1003

C语言常用宏定义技巧

  [复制链接]

出0入0汤圆

发表于 2006-3-1 14:06:50 | 显示全部楼层 |阅读模式
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(xxx)  ((byte) ((word)(xxx) & 255))



#define  WORD_HI(xxx)  ((byte) ((word)(xxx) >> 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



        



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



                   a++;}while(0)

出0入0汤圆

发表于 2006-3-1 15:16:01 | 显示全部楼层
帮你顶起来。

出0入0汤圆

发表于 2006-3-1 16:19:29 | 显示全部楼层
很好的学习材料!!! 谢谢

出0入0汤圆

 楼主| 发表于 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)  type  var##line

#define  __ANONYMOUS0(type, line)  ___ANONYMOUS1(type, _anonymous, line)

#define  ANONYMOUS(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、填充结构

#define  FILL(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

#define  GET_FILE_NAME(f)    _GET_FILE_NAME(f)

static char  FILE_NAME[] = GET_FILE_NAME(__FILE__);



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

#define  _TYPE_BUF_SIZE(type)  sizeof #type

#define  TYPE_BUF_SIZE(type)   _TYPE_BUF_SIZE(type)

char  buf[TYPE_BUF_SIZE(INT_MAX)];

     -->  char  buf[_TYPE_BUF_SIZE(0x7fffffff)];

     -->  char  buf[sizeof "0x7fffffff"];

这里相当于:

char  buf[11];

出0入0汤圆

发表于 2006-3-1 20:10:25 | 显示全部楼层
不错嘛.

出0入0汤圆

发表于 2006-3-1 20:59:32 | 显示全部楼层
愛生活, 愛頂你!!

出0入0汤圆

发表于 2006-3-2 16:18:12 | 显示全部楼层
收藏,仔细看看!

出0入0汤圆

发表于 2006-3-3 16:29:06 | 显示全部楼层
收藏待仔细看

出0入0汤圆

发表于 2006-3-3 19:48:35 | 显示全部楼层
好贴!顶!

出0入0汤圆

发表于 2006-3-3 20:39:23 | 显示全部楼层
我顶

出0入0汤圆

发表于 2006-3-4 15:03:57 | 显示全部楼层
楼主辛苦了。

编程就得有个好习惯。

出0入0汤圆

发表于 2006-3-4 18:15:49 | 显示全部楼层
多谢楼主的精彩总结!

出0入0汤圆

发表于 2006-3-4 18:34:44 | 显示全部楼层
好!

出0入0汤圆

发表于 2006-3-5 10:36:17 | 显示全部楼层
谢谢了

出0入0汤圆

发表于 2006-3-5 15:49:01 | 显示全部楼层
哦开!

出0入0汤圆

发表于 2006-3-5 17:15:06 | 显示全部楼层
收藏,仔细看看! 谢了

出0入0汤圆

发表于 2006-4-1 16:02:17 | 显示全部楼层
自相矛盾了 ,不介意用byte,而在后面的定义中自己却用了。呵呵,不好意思,有点叫真儿了。呵呵

出0入0汤圆

发表于 2006-4-6 12:32:20 | 显示全部楼层
谢谢

出0入296汤圆

发表于 2006-4-6 18:46:31 | 显示全部楼层
补充一点:

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

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



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

出0入0汤圆

发表于 2006-4-12 13:47:09 | 显示全部楼层
好东西!!

出0入0汤圆

发表于 2006-4-12 15:46:13 | 显示全部楼层
收获蛮大的~支持你

出0入0汤圆

发表于 2006-4-13 08:23:21 | 显示全部楼层
好东西,顶起来!!

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

出0入0汤圆

发表于 2006-4-14 00:08:06 | 显示全部楼层
说的清楚明白,多谢!

出0入0汤圆

发表于 2006-6-14 11:22:14 | 显示全部楼层
不错,再次顶!!

出0入0汤圆

发表于 2006-6-14 11:28:11 | 显示全部楼层
好文,好人!

出0入0汤圆

发表于 2006-7-19 16:44:12 | 显示全部楼层
不是很懂哦,但是看完必顶啊 。

出0入0汤圆

发表于 2006-7-19 16:57:07 | 显示全部楼层
统一  25楼

出0入0汤圆

发表于 2006-7-19 21:54:10 | 显示全部楼层
好东西,顶!

出0入0汤圆

发表于 2006-7-20 12:25:07 | 显示全部楼层
多谢楼主

出0入0汤圆

发表于 2006-7-20 17:14:43 | 显示全部楼层
楼主劳苦功高

出0入0汤圆

发表于 2006-7-20 20:16:42 | 显示全部楼层
多谢多谢!

楼主辛苦了。

出0入0汤圆

发表于 2006-7-21 13:19:02 | 显示全部楼层
我顶  我顶

出0入0汤圆

发表于 2006-7-21 14:45:50 | 显示全部楼层
抓紧时间学习

出0入0汤圆

发表于 2006-9-1 15:41:12 | 显示全部楼层
平时都是用汇编,正在努力转向C,多谢楼主提供这样好的资料(C学的烂啊,大部分东东的好处还没有看出来,呵呵~继续努力)

出0入0汤圆

发表于 2006-9-1 20:28:13 | 显示全部楼层
顶!

出0入0汤圆

发表于 2006-9-1 21:21:49 | 显示全部楼层
多谢楼主!感激涕零

出0入0汤圆

发表于 2006-9-2 06:53:47 | 显示全部楼层
谢谢!

出0入0汤圆

发表于 2006-9-2 08:10:44 | 显示全部楼层

出0入0汤圆

发表于 2006-9-2 12:11:50 | 显示全部楼层

出0入0汤圆

发表于 2006-10-26 09:46:32 | 显示全部楼层
好东西

多谢楼主

出0入0汤圆

发表于 2006-11-26 00:26:33 | 显示全部楼层
好东西,收下了.

出0入0汤圆

发表于 2006-11-26 13:06:28 | 显示全部楼层
我要说宏不好,该用inline为主了的话,相信有很多人会不同意的啊

出0入0汤圆

发表于 2006-11-27 09:02:13 | 显示全部楼层
好东西,谢谢

出0入0汤圆

发表于 2006-11-27 09:16:47 | 显示全部楼层
好!好!好!

出0入0汤圆

发表于 2006-11-27 11:20:11 | 显示全部楼层
好资料,认真学习~~

出0入0汤圆

发表于 2007-1-6 14:57:25 | 显示全部楼层
虽然没有全看懂,不过也受益.多谢!

出0入0汤圆

发表于 2007-2-27 13:36:47 | 显示全部楼层
好东西,顶!谢谢!

出0入0汤圆

发表于 2007-7-1 15:18:44 | 显示全部楼层
顶 顶

出0入0汤圆

发表于 2007-7-1 16:26:22 | 显示全部楼层
不错

真是个好东西!

出0入0汤圆

发表于 2007-7-1 19:51:52 | 显示全部楼层
很不错的学习材料

出0入0汤圆

发表于 2007-7-2 10:26:30 | 显示全部楼层
顶!

出0入0汤圆

发表于 2007-8-25 19:31:50 | 显示全部楼层
谢了,刚好遇到了#和##不能展开宏的问题。

出0入0汤圆

发表于 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)



刚学会的,谢谢

出0入0汤圆

发表于 2007-9-11 13:56:14 | 显示全部楼层
下载回去慢慢看~~

出0入0汤圆

发表于 2007-9-11 15:13:24 | 显示全部楼层
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)


用移位是不是更好?

出0入0汤圆

发表于 2007-9-11 16:37:10 | 显示全部楼层
顶一下

出0入0汤圆

发表于 2007-9-11 19:48:27 | 显示全部楼层
顶,好东东

出0入0汤圆

发表于 2007-9-12 10:56:15 | 显示全部楼层
不错,收藏了

出0入0汤圆

发表于 2007-9-12 12:57:55 | 显示全部楼层
好东西!

出0入0汤圆

发表于 2007-9-12 14:41:55 | 显示全部楼层
谢谢楼主,   感觉很经典, 但是不是12分明白, 要是再多有点注释就更好了。


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

出0入0汤圆

发表于 2007-9-13 12:03:39 | 显示全部楼层
收下了,谢谢,学习中

出0入0汤圆

发表于 2007-9-13 14:12:06 | 显示全部楼层
楼主辛苦了,学习中。

出0入0汤圆

发表于 2007-10-12 10:38:03 | 显示全部楼层
偶用的是uchar
uint
偶觉得这样用的人还是用的.不知上面为何没有...

出0入0汤圆

发表于 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
};

出0入0汤圆

发表于 2007-10-12 11:24:44 | 显示全部楼层
有些懂,有些不懂,慢慢学!谢谢!

出0入0汤圆

发表于 2007-10-12 14:02:19 | 显示全部楼层
再顶

出0入0汤圆

发表于 2007-12-19 14:41:03 | 显示全部楼层
very good

出0入0汤圆

发表于 2007-12-19 17:05:07 | 显示全部楼层
能不能用宏定义根据公式做一个存在程序区的数据表?

出0入0汤圆

发表于 2007-12-20 13:27:15 | 显示全部楼层

出0入0汤圆

发表于 2007-12-20 21:48:17 | 显示全部楼层
收藏先,再慢慢学。
好的习惯是成功的开始

出0入0汤圆

发表于 2007-12-21 09:09:38 | 显示全部楼层
好东西,我顶啊

出0入0汤圆

发表于 2007-12-21 09:29:53 | 显示全部楼层
好东西,谢谢楼主了

出0入0汤圆

发表于 2007-12-21 11:21:23 | 显示全部楼层
ding

出0入0汤圆

发表于 2007-12-21 14:59:08 | 显示全部楼层
收下了,谢谢,学习中

出0入0汤圆

发表于 2007-12-23 12:08:48 | 显示全部楼层
顶!

出0入0汤圆

发表于 2007-12-28 14:35:01 | 显示全部楼层
好东西,顶起来!

出0入0汤圆

发表于 2008-1-15 11:47:47 | 显示全部楼层

出0入0汤圆

发表于 2008-1-15 12:06:19 | 显示全部楼层
谢谢LZ!!!

出0入0汤圆

发表于 2008-1-15 15:11:11 | 显示全部楼层
bu cuo!!!!!!!!

出0入0汤圆

发表于 2008-1-15 15:16:16 | 显示全部楼层
ding!!!学习了

出0入0汤圆

发表于 2008-1-15 15:17:26 | 显示全部楼层
ding

出0入0汤圆

发表于 2008-1-15 22:40:18 | 显示全部楼层
记号

出0入0汤圆

发表于 2008-1-15 22:40:20 | 显示全部楼层
记号

出0入0汤圆

发表于 2008-1-25 16:22:43 | 显示全部楼层
打个烙印先,哪天要用就来查醒

出0入0汤圆

发表于 2008-1-25 19:25:36 | 显示全部楼层
很有用

出0入0汤圆

发表于 2008-1-25 21:07:08 | 显示全部楼层
可以啊~难得找到这样的文章~~~顶~~~

出0入0汤圆

发表于 2008-1-25 21:09:34 | 显示全部楼层
再来顶一次~~

出0入0汤圆

发表于 2008-1-25 21:13:42 | 显示全部楼层
我顶

出0入0汤圆

发表于 2008-1-26 10:45:24 | 显示全部楼层
收藏!!!!!!!!!1

出0入0汤圆

发表于 2008-1-26 15:12:09 | 显示全部楼层
顶起,顶起,不错。

出0入0汤圆

发表于 2008-1-26 15:31:18 | 显示全部楼层
楼主辛苦了。

出0入0汤圆

发表于 2008-4-3 13:52:02 | 显示全部楼层
好多还没用过,谢谢!

出0入0汤圆

发表于 2008-4-3 13:54:07 | 显示全部楼层
记录!

出0入0汤圆

发表于 2008-4-3 14:37:24 | 显示全部楼层
谢谢了

出0入0汤圆

发表于 2008-4-3 14:47:46 | 显示全部楼层

出0入0汤圆

发表于 2008-4-3 15:07:17 | 显示全部楼层
爱生活,爱阿莫

出0入0汤圆

发表于 2008-4-3 15:45:48 | 显示全部楼层
留个脚印!收下!

出0入0汤圆

发表于 2008-4-3 16:40:10 | 显示全部楼层
收下了

出0入46汤圆

发表于 2008-4-3 18:54:14 | 显示全部楼层
学习了

出0入0汤圆

发表于 2008-4-4 15:12:04 | 显示全部楼层
不顶不行呀
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子论坛 -- 东莞阿莫电子网站 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2023-1-30 00:53

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表