c语言的宏定义
忘了啥时候记的笔记了
@
宏定义
宏定义是C提供的三种预处理功能的其中一种,这三种预处理包括:宏定义、文件包含、条件编译
1.不带参数的宏定义:
宏定义又称为宏代换、宏替换,简称“宏”。 格式: #define 标识符 字符串 ,其中的标识符就是所谓的符号常量,也称为“宏名”。
预处理(预编译)工作也叫做宏展开:将宏名替换为字符串。 掌握"宏"概念的关键是“换”。一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。 即在对相关命令或语句的含义和功能作具体分析之前就要换:
例: #define PI 3.1415926
,把程序中出现的PI全部换成3.1415926
说明:
(1)宏名一般用大写
(2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义
(3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。
(4)宏定义末尾不加分号;
(5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。
(6)可以用#undef命令终止宏定义的作用域
(7)宏定义可以嵌套
(8)字符串" "中永远不包含宏
(9)宏定义不分配内存,变量定义分配内存。
2.带参数的宏定义:
除了一般的字符串替换,还要做参数代换
格式: #define 宏名(参数表) 字符串 例如:#define S(a,b) a * b ,area=S(3,2);第一步被换为area=a*b; ,第二步被换为area = 3 * 2;
类似于函数调用,有一个哑实结合的过程:
(1)实参如果是表达式容易出问题 ,#define S ( r ) r * r ,area=S(a+b);第一步换为area=r * r;,第二步被换为area=a+b * a+b; 正确的宏定义是#define S ( r ) (( r ) * ( r ))
(2)宏名和参数的括号间不能有空格
(3)宏替换只作替换,不做计算,不做表达式求解
(4)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存
(5)宏的哑实结合不存在类型,也没有类型转换。
(6)函数只有一个返回值,利用宏则可以设法得到多个值
(7)宏展开使源程序变长,函数调用不会
(8)宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)
C语言宏定义技巧(常用宏定义)
写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性
1,防止一个头文件被重复包含
#ifndef TEST_H // 1
#define TEST_H // 2
//.......... // 一些声明语句
#endif // 3
以上代码:如果没有定义TEST_H变量,就继续往下执行,如果定义了,就直接endif,即不做任何操作。
如果一个文件中包含了两个同样的头文件,那么第一次调用这个头文件的时候,没有定义TEST_H,经过1,到达2,定义TEST_H,进行代码段的执行,到3结束。但是当第二次调用头文件时,已经定义了TEST_H,所以就不会进行下面的代码声明了。这就是条件编译进行防止头文件包含的原理
define后面只要写个"文件名"保证其是一个独一无二的定义就可以了
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 */
当时写单片机的时候常用这东西。
3,得到指定地址上的一个字节或字
#define MEM_B( x ) ( *( (byte *) (x) ) )
#define MEM_W( x ) ( *( (word *) (x) ) )
这东西我没咋用过。倒是当年写汇编的时候会直接对内存地址进行操作,c我没这么用过,主要是不知道确切地址,
4,求最大值和最小值
#define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )
#define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )
三目运算符代替函数,算是常用的一个操作。
5,得到一个变量的地址(word宽度)
#define B_PTR( var ) ( (byte *) (void *) &(var) )
#define W_PTR( var ) ( (word *) (void *) &(var) )
6,得到一个字的低位和高位字节
#define WORD_LO(xxx) ((byte) ((word)(xxx) & 255)) //得到低位
#define WORD_HI(xxx) ((byte) ((word)(xxx) >> 8)) //得到高位
7,将一个字母转换为大写
#define UPCASE( c ) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )
当时比较菜
8,返回数组元素的个数
#define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )
也是个常用的方法,大一的时候比较菜,投机取巧嘛
9,宏定义防止使用是错误
用小括号包含。例如
#define ADD(a,b) (a+b)
可以看到上面的一些宏定义看上去有些是不必要的小括号,其实都是一次次试出来的,都是必要的