`

C宏定义的简单总结

阅读更多


今天在网上突然发现了下面几个关于c代码中的宏定义的说明,回想下,好像在系统的代码中也见过这些零散的定义,但没有注意,看到别人总结了下,发现果然很有用,虽然不知有的道可用与否,但也不失为一种手段,所以就先把它摘抄下来,增加一点见识:

1,防止一个头文件被重复包含 
#ifndef BODYDEF_H 
#define BODYDEF_H 
  //头文件内容 
#endif 
2,得到指定地址上的一个字节或字 
#define  MEM_B( x )  ( *( (byte *) (x) ) ) 
#define  MEM_W( x )  ( *( (word *) (x) ) ) 
3,得到一个field在结构体(struct)中的偏移量 
#define FPOS( type, field ) ( (dword) &(( type *) 0)-> field )
4,得到一个结构体中field所占用的字节数 
#define FSIZ( type, field ) sizeof( ((type *) 0)->field ) 
5,得到一个变量的地址(word宽度) 
#define  B_PTR( var )  ( (byte *) (void *) &(var) ) 
#define  W_PTR( var )  ( (word *) (void *) &(var) ) 
6,将一个字母转换为大写 
#define  UPCASE( c ) ( ((c) >= ''a'' && (c) <= ''z'') ? ((c) - 0x20) : (c) ) 
7,判断字符是不是10进值的数字 
#define  DECCHK( c ) ((c) >= ''0'' && (c) <= ''9'') 
8,判断字符是不是16进值的数字 
#define  HEXCHK( c ) ( ((c) >= ''0'' && (c) <= ''9'') ||((c) >= ''A'' && (c) <= ''F'') ||((c) >= ''a'' && (c) <= ''f'') ) 
9,防止溢出的一个方法 
#define  INC_SAT( val )  (val = ((val)+1 > (val)) ? (val)+1 : (val)) 
10,返回数组元素的个数 
#define  ARR_SIZE( a )  ( sizeof( (a) ) / sizeof( (a[0]) ) ) 
11,使用一些宏跟踪调试 
ANSI标准说明了五个预定义的宏名。它们是: 
_LINE_ (两个下划线),对应%d
_FILE_     对应%s
_DATE_   对应%s
_TIME_    对应%s
_STDC_ 

 
宏中"#"和"##"的用法
我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起.
#define STR(s)     #s 
#define CONS(a,b)  int(a##e##b) 
Printf(STR(vck));           // 输出字符串"vck" 
printf("%d\n", CONS(2,3));  // 2e3 输出:2000 

当宏参数是另一个宏的时候 
需要注意的是凡宏定义里有用"#"或"##"的地方宏参数是不会再展开. 
#define A          (2) 
#define STR(s)     #s 
#define CONS(a,b)  int(a##e##b) 
printf("%s\n", CONS(A, A));               // compile error  
这一行则是: 
printf("%s\n", int(AeA)); 
INT_MAX和A都不会再被展开, 然而解决这个问题的方法很简单. 加多一层中间转换宏. 
加这层宏的用意是把所有宏的参数在这层里全部展开, 那么在转换宏里的那一个宏(_STR)就能得到正确的宏参数
#define STR(s)      _STR(s)          // 转换宏 
#define CONS(a,b)   _CONS(a,b)       // 转换宏 
printf("int max: %s\n", STR(INT_MAX));          // INT_MAX,int型的最大值,为一个变量 #include<climits> 
输出为: int max: 0x7fffffff 
STR(INT_MAX) -->  _STR(0x7fffffff) 然后再转换成字符串; 

printf("%d\n", 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]; 

分享到:
评论

相关推荐

    巧用C语言宏定义实现自动注释调试代码

    总结来说,C语言中的宏定义在调试代码时能发挥以下作用: 1. 条件编译:根据宏定义的状态决定是否执行特定代码。 2. 自动注释:通过宏定义可以快速开关调试信息,简化代码维护。 3. 提供位置信息:利用预定义宏如`__...

    C语言宏定义技巧

    C语言宏定义是一种预处理机制,它允许程序员创建符号常量和简单的代码替换规则,以增强代码的可读性、可维护性和通用性。宏定义主要有两种类型:不带参数的宏定义和带参数的宏定义。 不带参数的宏定义通过`#define`...

    C语言常用宏定义技巧

    本文将详细介绍一些常用的C语言宏定义技巧,并通过具体示例进行说明。 #### 二、防止头文件重复包含 为了避免在多个源文件中多次包含同一个头文件导致的编译错误,通常会采用条件预处理指令来避免重复包含问题。...

    C语言宏定义使用技巧.pdf

    总结来说,C语言宏定义使用技巧包括数据类型定义、计算和操作函数、位操作、内存地址操作、条件编译、特定数值计算和字符处理等。通过合理地使用宏定义,可以提高代码的可读性、可维护性以及性能。然而,宏定义的...

    dll导出导入宏定义使用总结

    ### DLL导出与导入宏定义使用总结 #### 引言 动态链接库(Dynamic Link Library,简称DLL)是Windows系统中的一个重要组成部分,广泛应用于软件开发过程中。通过DLL,可以实现代码及数据的共享,提高软件的运行...

    c语言带参数的宏定义

    无参数的宏定义简单地用一个字符串替换宏名,而带参数的宏则可以根据传入的实际参数进行更复杂的文本替换。 #### 三、带参数宏定义的语法 带参数的宏定义的基本语法格式如下: ```c #define 宏名(形参列表) 替换...

    宏定义#define用法总结

    本文将对宏定义的用法进行总结,包括简单的宏定义、带参数的宏、宏的特殊单行定义、多行定义、条件编译、取消宏等。 1. 简单的宏定义 宏定义的基本语法是 #define 标识符 替换列表,例如 #define N 100,这样在...

    单片机宏定义学习手记

    总结来说,单片机宏定义学习手记向我们展示了宏定义在单片机编程中的重要性和实用性。通过宏定义,程序员可以实现代码的重用、提高代码的可读性、减少重复性劳动,并为复杂的硬件操作提供简化的编程接口。掌握宏定义...

    C语言宏定义中#与##运算符

    ### C语言宏定义中#与##运算符详解 #### 一、引言 在C语言中,宏定义是一种非常强大的工具,它可以帮助程序员简化代码、提高编程效率。宏定义不仅支持简单的文本替换,还提供了两个特殊的运算符:`#` 和 `##`。...

    51单片机的C语言宏定义应用[参考].pdf

    总结来说,51单片机的C语言宏定义应用提供了强大的文本替换功能,通过宏定义,我们可以创建自定义的常量、简化复杂的表达式以及实现条件编译,从而提高代码的可复用性和可维护性。在编写51单片机程序时,合理运用宏...

    宏定义和函数调用的区别

    在探讨宏定义与函数调用的区别时,我们深入解析它们在C语言编程中的特性、应用场景以及潜在风险,以便更全面地理解这两种编程机制。 ### 宏定义与函数调用的本质区别 #### 宏定义(#define) 宏定义是预处理器的一...

    #define 宏定义的一些用法总结

    ### #define宏定义的一些用法总结 #### 一、引言 在C及C++编程中,`#define`是一个非常强大的预处理器指令,用于创建宏。宏可以在编译前阶段替代代码片段,提高代码的复用性与可维护性。本文将详细探讨`#define`的...

    常用宏定义#define

    总结来说,`#define`宏定义在C/C++编程中起着重要作用,能够提高代码的灵活性和可维护性。然而,由于宏定义在编译阶段进行文本替换,可能存在副作用和类型安全问题。因此,在使用宏定义时,需谨慎处理,尤其是在处理...

    宏定义和别名在 Windows 编程上的应用

    另一方面,宏定义是C语言预处理的一部分,它可以实现简单的文本替换。例如,`#define MAXTIME 1000`定义了一个宏`MAXTIME`,其值为1000。在代码中,`if (i )`会被编译器替换为`if (i )`。然而,宏定义并不进行类型...

    C语言#define拼接宏定义实现方式

    总结一下,C语言中的宏定义,尤其是结合拼接操作,可以实现强大的文本替换功能。通过巧妙地设计宏,我们可以简化复杂的代码结构,提高代码复用,同时降低出错的可能性。然而,过度依赖宏可能导致代码难以理解和调试...

    宏定义应用举例.zip

    总结来说,这个压缩包提供了一个学习和练习C语言宏定义的平台,通过"ex39.c"的实际代码,我们可以看到宏定义在实际编程中的应用,同时"重要说明.txt"将帮助我们理解宏定义的使用技巧和注意事项。而其他辅助文件则有...

    宏定义解析

    ### 宏定义解析 #### 一、宏定义概述 ...然而,由于宏定义仅仅是在编译前进行简单的字符串替换,因此在使用时需要注意一些细节,比如正确使用括号、理解宏定义的作用域以及区分宏定义与`typedef`等概念。

    AVR最强的宏定义

    在C语言中,宏定义是一种预处理指令,用于创建常量或简单的函数替代。在AVR微控制器的编程中,宏定义通常用于定义寄存器的别名、位操作等,以便于更直观地理解和编写代码。 #### 三、核心宏定义解析 根据提供的...

    关于宏定义带参数可能会出现的分号错误问题

    宏定义是C语言中的一个重要特性,主要用于代码的预处理阶段。通过宏定义可以实现代码的替换、简化编程过程等目的。其中,带参数的宏定义能够根据传入的不同参数值产生不同的效果,从而提供更强大的功能。然而,在...

Global site tag (gtag.js) - Google Analytics