zoukankan      html  css  js  c++  java
  • 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 */ 

    分析:
    #include 
    typedef struct person {
        int num;
        int age;
        char name[20];
    }person;
    #define FPOS(type,field) sizeof(((type *)0)->field)
    main()
    {
        printf("%d ",FPOS(person,name));
    }
    ^_^[sunny@localhost ~]52$ ./a.out 
    20

    #define OFFSETOF(type, field) ((size_t)&(((type *)0)->field))

    (type *)0:把0地址当成type类型的指针。

    ((type *)0)->field:对应域的变量。

    &((type *)0)->field:取该变量的地址,其实就等于该域相对于0地址的偏移量。

    (size_t)&(((type *)0)->field):将该地址(偏移量)转化为size_t型数据。

    ANSI C标准允许任何值为0的常量被强制转换成任何一种类型的指针,并且转换结果是一个NULL指针,因此((s*)0)的结果就是一个类型为s*的NULL指 针。如果利用这个NULL指针来访问s的成员当然是非法的,但&(((s*)0)->m)的意图并非想存取s字段内容,而仅仅是计算当结构 体实例的首址为((s*)0)时m字段的地址。聪明的编译器根本就不生成访问m的代码,而仅仅是根据s的内存布局和结构体实例首址在编译期计算这个(常 量)地址,这样就完全避免了通过NULL指针访问内存的问题。

    有人这样表达:

    #define OFFSETOF(type, field) ((size_t)

                   ((char *)&((type *)0)->field - (char *)(type *)0))

    我认为效果是一样的,多增加的那部分就是0地 址,相减后就是偏移量。

    为什么要增加size_t呢?

    首先size_t的定义是什么呢,在文件 stddef.h中可以找到答案。

    typedef unsigned int size_t;                      /*mine is 32bit machine*/

    可见就是将偏移量转化为无符整型,其实32位 机器的地址就是无符号的32位整数。一般情况下,不进行size_t类型转化也是没有问题的(后面的实验可证)。我认为,只有偏移量足够大,当大于 0x80000000时才有影响,因为这时候的偏移量最高位是1,机器默认为是负数了。似乎上面宏定义OFFSETOF中更能说明这个问题,因为这个宏定 义是一个差值,最高位是1就肯定是负数了。使用printf("%d", &var);打印一个变量的地址就是个负数。这只是我的看法,网上基本没有什么人分析为什么添加size_t的强制类型转化。因为系统对数组长度 的大小是有限制的,所以也不能实验得到数据。



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

     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,dateprintf(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,ba+b

                       a++; 

    应 用时:if(….) 

              DO(
    a,b); //产 生错误 

            else 

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

                       a++;}while(0) 
    宏 中"#"和"##"的用法 
    一、一般用法
     
    我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起

    用法

    #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]; 

  • 相关阅读:
    JS BOM对象 History对象 Location对象
    JS 字符串对象 数组对象 函数对象 函数作用域
    JS 引入方式 基本数据类型 运算符 控制语句 循环 异常
    Pycharm Html CSS JS 快捷方式创建元素
    CSS 内外边距 float positio属性
    CSS 颜色 字体 背景 文本 边框 列表 display属性
    【Android】RxJava的使用(三)转换——map、flatMap
    【Android】RxJava的使用(二)Action
    【Android】RxJava的使用(一)基本用法
    【Android】Retrofit 2.0 的使用
  • 原文地址:https://www.cnblogs.com/guyandianzi/p/8582638.html
Copyright © 2011-2022 走看看