宏定义#define详解

  1. #define主要功能

  • c语言中用到很多宏定义 ,为了头文件被重复用到#ifndef  #define,#ifdefine  edfif等条件编译
  • 宏不是语句,结尾不用加“;”,否则会被替换进进程中
  • #表示这是一条预处理指令
  • 如果写宏不止一行,则在结尾加反斜杠使多行能连接上,但第二行要对齐,否则空格也会作为替换文本的一部分

  2.无参宏

  • 无参宏即宏名之后不带参数,只是简单的文本替换
  • #define与typedef区别
    • 两者都可以表示数据类型  1 #define INIT1 int 2 typedef in UINT2 
    • 但有时候也会有区别比如定义指针类型的变量时
    • 1 #define INT1 int *
      2 typedef int * INT2;
      3 INT1 a1, b1;
      4 INT2 a2, b2;

    • INT1 a1,b1;被替换后为 int *a1,b1;即一个指向int类型的指针一个int类型的变量
    • INT2  a2,b2;则是两个指向int类型的指针

3.有参宏

  • 带参数的宏定义,宏名中不能有空格,宏名与形参表之间也不能有空格,而形参表中形参之间可以有空格

 

  • 有参宏实现一个数的平方
    • 1 #define COUNT(M) M*M
      2 int x=6;
      3 print(COUNT(x+1));
      4 print(COUNT(++X));
      5 结果输出:13   和56
      而不是函数的输出49和

      • 原因在于预编译器不进行技术,只是进行简单的文本替换,COUNT(x+1)被替换成COUNT(x+1*x+1)
      • CUNT(++x)被替换成++x*++x即为7*8=56而不是想要的7*7=49,连续前置自加加两次
      • 解决办法是用括号将整个替换文本及每个参数用括号括起来但即便是加上括号也不能解决第二种情况,所以解决办法是尽量不使用++,-等符号
  • 函数实现一个数的平方
    • 1 int count(int x)
      2 {
      3 return x*x
      4 }

 

  • 有参宏与函数区别
    • 在宏定义#define COUNT(M) M*M中的形参不分配内存单元,不做类型定义,只是简单的文本替换,而函数int count(int x)中形参x是局部变量,会在栈区分配内存单元,所以要做类型定义,而且实参与形参之间是值传递。而宏只是符号代换,不存在值传递。

 

  • 宏定义也可以定义表达式或多个语句
    • #define AB(a,b) a=i+5;b=j+3;   宏定义多个语句
      int i=3,j=5;
      int m-0,n=0;
      AB(m,n);       //宏替换后为m=i+5,n=j+3;
      print("m=%d,n=%d",m,n);
      
      输出结果:m=8,n=8

  4.#运算符

  • #的作用就是将#后边的宏参数进行字符串的操作,也就是将#后边的参数两边加上一对双引号使其成为字符串。例如a是一个宏的形参,则替换文本中的#a被系统转化为"a",这个转换过程即为字符串化。
  • 1 #define TEST(param) #param
    2 
    3 char *pStr=TEST(123);
    4 printf("pSrt=%s\n",pStr);
    5 
    6 输出结果为字符  ”123

     

5.##运算符

  • ##运算符也可以用在替换文本中,它的作用起到粘合的作用,即将两个宏参数连接为一个数
  • 1 #define TEST(param1,param2) (param1##param2)
    2 
    3 int num =TEST(12,34);
    4 printf("num=%d\n",num);
    5 
    6 输出结果为:num=1234

     

6.可变宏:...和_VA_ARGS_

  • 作用主要是为了方便管理软件中的打印信息。在写代码或DEBUG时通常需要将一些重要参数打印出来,但在软件发行的时候不希望有这些打印,这时就用到可变参数宏了。
  • 1 # define PR(...) printf(_VA_ARGS_)
    2 PR("hello\n");
    3 
    4 输出结果:hello
    • 在宏定义中,形参列表的最后一个参数为省略号...,而“_VA_ARGS_”被用在替换文本中,来表示省略号...代表了什么。
  • 1 #define PR1(X,...) printf("Message"#X":"_VA_ARGS_)
    2 double mes=10;
    3 PR1(1,"msg=%.2f\n",msg);
    4 
    5 输出结果:Message1:msg=10.00
    6 
    7 宏替换后为:printf(Message""1""msg=%.2f\n",msg);
    • 需要注意的是:省略号...只能用来替换宏的形参列表中的最后一个。如#define PR1(x,...,y)则是错误的。



7.成熟软件中常用的宏定义。

  • 防止头文件被重复包含
    • 1 #ifndef COMDEF_H
      2 
      3 #define COMDEF_H
      4 //头文件的内容
      5 
      6 #endif
  • 得到一个制定地址上的一个字节或字
    • 1 #define MEM_B(X) (*((byte*)(x)))
      2 #define MEM_W(X) (*((word*)(x)))
  • 求最大值与最小值
    • 1 #define MAX(x,y)  ((x)>(y)?(x):(y))
      2 #define MIN(x,y)  ((x)<(y)?(x):(y))
  • 得到一个结构体中field所占用的字节数
    • 1 #define FSIZ(type,field)  sizeof(((type*)0)->field)
  • 得到一个field在结构体中的偏移量
    • 1 #define FPOS(type,field)\
      2                     ((dword)&(((type*)0)->field)
  • 按照LSB格式把两个字节转化为一个word
    • 1 #define FLIPW(ray) (((word)(ray)[0]*256)+(ray)[1])
  • 按照LSB格式将一个WORD转化为两个字节
    • 1 #define FLOPW(ray,val)  (ray)[0]=((val)/256);(ray)[1]=((val)&0xFF)
  • 得到一个变量的地址
    • 1 #define B_PTR(var) ((byte*)(void*)&(var))
      2 #define W_PTR(var) ((word*)(void*)&(var))
  • 得到一个字的高位与低位字节
    • 1 #define WORD_LO(xxx) ((byte)((word)(xxx)&255))
      2 #define WORD_HI(xxx) ((byte)((word)(xxx)>>8))
  •  用宏得到一个数组所含的元素个数
    • 1 #define ARR_SIZE(a) (sizeof(a)/sizeof((a)[0]))

 

posted @ 2018-12-21 12:17  long_ago  阅读(10649)  评论(1编辑  收藏  举报