C语言的#define用法
1. 简单的宏定义
#define MAXSIZE 1000
// 有点像简单的文本替换
2. define的函数定义
// 同样类似简单文本替换
#define Add(a,b) a+b
// 要注意可能会出现运算优先级的问题,比如
c*Add(a,b)*d;
// 本意是c*(a+b)*d,但是计算机可能理解为:c*a+b*d
3. 宏的单行定义和多行定义
宏定义中允许包含两行以上命令的情形,此时必须在最右边加上\
且该行\
后不能再有任何字符,连注释部分都不能有,下面的每行最后的一定要是\
,\
后面加一个空格都会报错,更不能跟注释。
#define max(a,b) \
(((a)>(b))?(a):(b))\
4. 条件编译
在大规模的开发过程中,特别是跨平台和系统的软件里,define最重要的功能是条件编译。
#ifdef WINDOWS
...
#endif
#ifdef LINUX
...
#endif
5. 取消定义宏
//定义宏
#define [MacroName] [MacroValue]
//取消定义
#undef [MacroName]
6. 重复包含(定义)
由于头文件包含可以嵌套,那么C文件就有可能包含多次同一个头文件,就可能出现重复定义的问题的。通过条件编译开关来避免重复包含(重复定义)
#ifndef __headerfileXXX__
#define __headerfileXXX__
//头文件内容
#endif
7. 重新定义类型
重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植。
补充:关于unsiged char和char
首先在内存中,char与unsigned char没有什么不同,都是一个字节,唯一的区别是,char的最高位为符号位,因此char能表示-128~127,unsigned char没有符号位,因此能表示0~255,这个好理解,8个bit,最多256种情况,因此无论如何都能表示256个数字。
在实际使用过程种有什么区别呢?主要是符号位,但是在普通的赋值,读写文件和网络字节流都没什么区别,反正就是一个字节,不管最高位是什么,最终的读取结果都一样,只是你怎么理解最高位而已,在屏幕上面的显示可能不一样。
二者的最大区别是:但是我们却发现在表示byte时,都用unsigned char,这是为什么呢?首先我们通常意义上理解,byte没有什么符号位之说,更重要的是如果将byte的值赋给int,long等数据类型时,系统会做一些额外的工作。如果是char,那么系统认为最高位是符号位,而int可能是16或者32位,那么会对最高位进行扩展(注意,赋给unsigned int也会扩展)而如果是unsigned char,那么不会扩展。最高位若为0时,二者没有区别,若为1时,则有区别了。同理可以推导到其它的类型,比如short, unsigned short,等等。
typedef unsigned char boolean; /* Boolean value type. */
8. 一些常用用法
1. 得到一个field在结构体中的偏移量
#define OFFSETOF(type, field) ((size_t)&(((type *)0)->field))
(type*)0
表示把0地址当成type类型的指针 ((type *)0)->field
表示对于
域的变量。前面加上&表示取得地址(也就是相对于0的偏移量),然后将该偏移量转换为size_t类型的数据
2. 得到一个结构体中field所占用的字节数
#define FPOS( type, field ) ( (dword) &(( type *) 0)-> field )
3. 按照LSB格式把两个字节转化为一个Word
#define FLIPW( ray ) ( (((word) (ray)[0]) * 256) + (ray)[1] )
4. 得到一个变量的地址(word宽度)
#define B_PTR(var) ((byte*)(void *) &(var))
#define W_PTR( var ) ((word *)(void *) &(var))
5. 得到一个字的高位和低位字节
#define WORD_LO(xxx) ((byte) ((word)(xxx) & 255))
#define WORD_HI(xxx) ((byte) ((word)(xxx) >> 8))
9. 使用一些宏跟踪调试
五个预定义的宏名:
__LINE__ 及 __FILE__ //宏指示,#line指令可以改变它的值,简单的讲,编译时,它们包含程序的当前行数和文件名。
__DATE__ 宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。
__TIME__ 宏指令包含程序编译的时间。时间用字符串表示,其形式为:分:秒
__STDC__ 宏指令的意义是编译时定义的。一般来讲,如果__STDC__已经定义,编译器将仅接受不包含任何非标准扩展的标准C/C++代码。如果实现是标准的,则宏__STDC__含有十进制常量1。如果它含有任何其它数,则实现是非标准的。;
// 定义_DEBUG
#ifdef _DEBUG
#define DEBUGMSG(msg,date) printf(msg);printf(“%d%d%d”,date,_LINE_,_FILE_)
#else
#define DEBUGMSG(msg,date)
#endif
10. 一些特殊的标识符
## 是简单的连接符,#@用来给参数加单引号,#用来给参数加双引号即转成字符串。