预定义符号:
__FILE__:进行编译的源文件
__LINE__:文件当前行号
__DATE__:文件被编译的日期
__TIME__:文件被编译的时间
define:
- #define定义标识符:
#define MAX 1000;
1.如果定义的内容太长,可以分成几行,但是每一行后面都要加上一个/(续行符)
2.define定义标识符的时候最好不要在后面加上;这样容易导致问题
- #define定义宏:允许把参数替换到文本中
#define name(parament - list) stuff
注:左括号(必须与name紧邻,如果俩者之间有任何空白,参数列表就会被解释成stuff的一部分
#define SQUARE(x) ((x)*(x))
注:宏定义时,一定不要吝啬加括号,该加括号的地方都应加上,否则可能会出现错误
宏参数和define定义中可以出现其他#define定义的变量,但是对于宏,不能出现递归
##和#
字符串有自动连接的特点
char *p = "hello""bit\n";
printf("hello""bit\n");
printf("%s\n", p);
如何把宏参数插入到字符串中?
1.将字符串作为参数,
2.使用#,把宏参数变成对应的字符串
#define PRINT(FORMAT,VALUE)\
printf("the value of " #VALUE " is "FORMAT"\n", VALUE);
int main()
{
int i = 10;
PRINT("%d", i+3);
return 0;
}
//编译器会把代码中的#VALUE预处理为“VALUE”
3.## 可以把位于它俩边的符号合成一个符号,它允许宏定义从分离的文本片段中创建标识符
#define CAT(X,Y) X##Y
int main()
{
int val9 = 10;
printf("%d", CAT(val, 9));
return 0;
}
//输出10,因为编译器会将val和9连接在一起变成val9,等于=10
注:这样的连接必须阐述一个合法的标识符,否则其结果就未定义的
宏和函数
命名约定:
宏名全部大写
函数名不要全部大写
宏通常用于执行简单的运算,比如在俩个数中找大的一个
#define MAX(a,b) ((a)>(b)?(a):(b))
为什么不用函数来完成这个任务呢?
- 用于调用函数和从函数返回代码可能比实际执行这个小型计算工作所需的实际更多,所以宏比函数在程序规模和速度方面更胜一筹。
- 宏和类型无关
宏和函数相比其劣势:
- 每次使用宏的时候,就会将一份宏定义的代码插入带程序中。除非宏比较短,否则可能大幅度增加程序的长度
- 宏没有办法调试
- 宏和类型无关,不够严谨
- 宏可能会带来运算符优先级的问题,容易导致程序出错
但是宏也可以做一些函数做不到的事,比如宏的参数可以事类型
宏和函数的对比:
1.代码长度:
宏:每次使用宏的时候,就会将一份宏定义的代码插入带程序中。除非宏比较短,否则可能大幅度增加程序的长度
函数:函数的代码只出现在一个地方,每次使用函数,都调用同一个地方的代码
2.执行速度:
宏:赶快
函数:存在函数调用/返回的额外开销
3.操作符的优先级:
宏:宏参数要给他们加上括号,否则邻近的操作符的优先级可能会产生不可预料的结果
函数:函数只在函数调用的时候求值一次,他的结果值传递给函数,表达式的结果更容易预测
4.参数求值
宏:参数每次都要重新求值,由于多次求值,具有副作用的参数可能会产生不可预测的结果
函数:函数只在函数调用的时候求值一次,参数的副作用并不会造成任何特殊的问题
5.参数类型:
宏:宏与类型无关,只要参数合法,它可以使用任何类型
函数:参数与类型有关,参数类型不同就要使用不同的函数,即使他们所做的任务相同
注:在c++中尽量不要用#define
- c++可以用const之间定义为常量‘
- c++可以用内联(inline)
移除一个宏定义:#undef
带有副作用的宏:
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么在使用这个宏的时候就会出现危险,导致不可预测的结果。副作用就是表达式求值的时候出现的永久性效果
x+1;不带副作用
x++;带副作用
#define MAX(a,b) ((a)>(b)?(a):(b))
int main()
{
int x = 5;
int y = 8;
int z = MAX(x++, y++);
reruen 0;
}
//输出x=6,y=10,z =9;
//处理后z = (x++)>(y++)?(x++):(y++);