前面两篇文章我们介绍了基础的数据类型和C语言的关键字,这一篇我们总结整理一下C语言的编程过程中经常会用到宏定义。
如果你只是使用宏定义做一些常量的定义,那么你不是OUT了,就是C语言小白。
我们在编程过程中,宏定义都有哪些作用呢
- 常量定义
- 可以作为功能代码的开关
- 防止头文件被重复包含
- 定义一些通用类型,防止因为平台和编译器不同导致的类型差异,方便移植
- 其他高级浮夸用法
好了,各位看官一起来看一下使用的例子吧
一. 常量定义
#define PI 3.1415926 //定义π值,代码易读 #define MAX_LEN 1024 //定义常数,不像const修饰的变量要占用空间
二.防止头文件重复包含
#ifndef COMDEF_H #define COMDEF_H //头文件内容 #endif
三.重定义数据类型,方便移植
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 */
四. 宏函数
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) //请注意这里的括号,一定要加,否则会有意外惊喜 //宏定义实现一个参数交换 #define SWAP(X, Y) \ X = X + Y; \ Y = X - Y; \ X = X - Y;
再来看一下求数组的最大最小值是不是非常简洁
maxvalue =minvalue = a[0]; for(i = 1; i < MAXLEN; i++) { maxvalue = MAX(maxvalue, a[i]); minvalue = MIN(minvalue , a[i]); }
五. 作为开关使用
#ifdef DEBUG_MODE //在调试模式下(DEBUG_MODE在之前被定义)才会将代码编译进去 …… #endif #if (KEY_ON) //可以根据宏定义KEY_ON的真假来选择代码进行编译 …… #else …… #endif
六. 作为字符串或者连字符使用
在宏体中,如果宏体所在标示符中有##,那么在宏体扩展的时候,宏参数会被直接替换到标示符中。如:
#define COMMAND(NAME) { #NAME, NAME ## _command } struct command { char *name; void (*function) (void); };
在宏扩展的时候
struct command commands[] = { COMMAND (quit), COMMAND (help), ... };
会被扩展成:
struct command commands[] = { { "quit", quit_command }, { "help", help_command }, ... };
这样就节省了大量时间,提高效率。
七.协助调试的宏定义
- __LINE__ 及 __FILE__ 宏指示,#line指令可以改变它的值,简单的讲,编译时,它们包含程序的当前行数和文件名 。
- __DATE__ 宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。
- __TIME__ 宏指令包含程序编译的时间。时间用字符串表示,其形式为 时: 分:秒
- __STDC__ 宏指令的意义是编译时定义的。一般来讲,如果__STDC__已经定义,编译器将仅接受不包含任何非标准扩展的标准C/C++代码。如果实现是标准的,则宏__STDC__含有十进制常量1。如果它含有任何其它数,则实现是非标准的。
八. 其他调试用特殊宏定义
例1. 作为块注释,非常的好用,对于一些编辑器,还会自动变灰,方便阅读
#if 0 /*your code, want not use*/ #endif
例2. 宏定义连接字符串
#define MAINVER 2 #define SUBVER1 0 #define SUBVER2 1 #define STR(s) #s #define VERSION(a,b,c) "System V" STR(a) "." STR(b) "." STR(c) " "__DATE__ #define VERSTR "System V2.0.1.2017.9.13"
例3. 得到指定地址上的一个字节或字
#define MEM_B(x) (*((byte *) (x))) #define MEM_W(x) (*((word *) (x)))
例4. 得到一个field在结构体(struct)中的偏移量
#define FPOS(type, field) ((dword) &((type *) 0)-> field)
例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])))
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
暂无评论...