#define简单总结

C primer plus 第十六章

Definition

The #define Directive

You can use the #define directive to give a meaningful name to a constant in your program. The two forms of the syntax are:

Syntax

#define identifier token-stringopt

#define identifier[( identifieropt, ... , identifieropt )] token-stringopt

##明示常量

#define Pi 3.14
#define PX printf("X is %d.\n", x)

##在#define中使用参数

#define SQUARE(X) X*X /*SQAURE(x+2) --> x+2*x+2*/
#define SQUARE(X) (X)*(X) /*100/SQUARE(2) --> 100/(2)*(2)*/
#define SQUARE(X) ((X)*(X)) /*SQUARE(++x) --> 视编译器不同可能得出不同的结果, 如结果等于(x+1)*(x+2)或者(x+2)*(x+2) 所以尽量避免在宏定义中使用++x*/

##用宏参数创建字符串: #运算符

#define PSQR(x) printf("The square of " #x " is %d.\n",((x)*(x)))

int main(void)
{ 
	int y = 5;
	PSQR(y);
	PSQR(2 + 4);
	return 0;
}

输出如下:

The square of y is 25.
The square of 2 + 4 is 36.

调用第一个宏的时候, 用"y"替换#x. 调用第二个宏的时候, 用"2 + 4"替换#x. ANSI C 字符串的串联特性将这些字符串与printf()语句的其它字符串组合, 生成最终的字符串. 例如, 第一次调用变为:

printf("The square of " "y" " is %d.\n", ((y)(y)));

然后, 字符串串联功能将这3个相邻的字符串组合成一个字符串:

"The square of y is %d.\n"

#undef指令

#define LIMIT 100
/*
a lot of codes
*/
#undef LIMIT //就是取消已定义的LIMIT

有些预定义的宏是不能取消的, 如__DATE__等

##常用的#define语句

  1. 得到指定地址上的一个字节或字

    #define  MEM_B(x)  ( *( (byte *) (x) ) )
    #define  MEM_W(x)  ( *( (word *) (x) ) )
    
  2. 求最大值和最小值

    #define  MAX(x,y) ( ((x) > (y)) ? (x) : (y) )
    #define  MIN(x,y) ( ((x) < (y)) ? (x) : (y) )
    
  3. 得到一个field在结构体(struct)中的偏移量

    #define FPOS(type, field) /
    /*lint -e545 */ ( (dword) &(( type *) 0)-> field ) /*lint +e545 */
    
  4. 得到一个结构体中field所占用的字节数

    #define FSIZ(type, field) sizeof( ((type *) 0)->field )
    
  5. 按照LSB格式把两个字节转化为一个Word

    #define  FLIPW(ray) ( (((word) (ray)[0]) * 256) + (ray)[1] )
    
  6. 得到一个变量的地址(word宽度)

    #define  B_PTR(var)  ( (byte *) (void *) &(var) )
    #define  W_PTR(var)  ( (word *) (void *) &(var) )
    
  7. 得到一个字的高位和低位字节

    #define  WORD_LO(xxx)  ((byte) ((word)(xxx) & 255))
    #define  WORD_HI(xxx)  ((byte) ((word)(xxx) >> 8))
    
  8. 返回一个比X大的最接近的8的倍数

    #define RND8(x)       ((((x) + 7) / 8 ) * 8 )
    
  9. 将一个字母转换为大写

    #define  UPCASE(c) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c))
    
  10. 判断字符是不是10进值的数字

    #define  DECCHK(c) ((c) >= '0' && (c) <= '9')
    
  11. 判断字符是不是16进值的数字

    #define  HEXCHK(c) ( ((c) >= '0' && (c) <= '9') ||/
    
    ((c) >= 'A' && (c) <= 'F') ||/
    
    ((c) >= 'a' && (c) <= 'f') )
    
  12. 防止溢出的一个方法

    #define  INC_SAT(val)  (val = ((val)+1 > (val)) ? (val)+1 : (val))
    
  13. 返回数组元素的个数

    #define  ARR_SIZE(a)  ( sizeof( (a) ) / sizeof( (a[0]) ) )
    
  14. 返回一个无符号数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) )
    
  15. 对于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)))
    
  16. #define中的特殊标识符

    #define Conn(x,y) x##y
    #define ToChar(x) #@x
    #define ToString(x) #x
    
    int a=Conn(12,34);//a=1234, ##是连接
    char b=ToChar(a);//b='a', #@用来给参数加单引号
    char c[]=ToString(a);//c="1234", #用来给参数加双引号
    
  17. LOG日志与do{}while(0)

    #include <stdio.h>
    #include <stdlib.h>
    #define BUFSIZE 1024
    #define LOG(str) \
    do \
    {\
        fprintf(stderr, "[%s:%d %s %s]:%s\r\n",  __FILE__, __LINE__, __DATE__, __TIME__, str); \
    }while(0)
    int main()
    {
        char *buf = (char *)malloc(BUFSIZE);
        LOG("malloc for buf");
        free(buf);
        return 0;
    }
    

输出为: [macro.c:12 Jan 13 2019 22:38:33]:malloc for buf