预定义符号:
__FILE__:进行编译的源文件当前位置
__LINE__:文件当前的行号
__DATE__:文件被编译的日期
__TIME__:文件被编译的时间
这些预定义符号都是语言内置的
预处理指令:
#difine name stuff
#define MAX 100
#define STR "hello"
#define REG register//为register这个关键字,创建一个简短的名字
#define do_forever for(;;)//用符号来替换一种实现
#define 定义宏:
#define机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏或者定义宏
宏的申明方式:
#define name(parament-list) stuff其中的parament-list是一个由逗号隔开的符号表,它们可能 出现在stuff中
#define SQUARE(X) X*X
int main()
{
int ret = SQUARE(5);
printf("%d", ret);
return 0;
}
提示:用于数值表达式进行求值的宏定义应该加上括号,避免在使用宏时由于参数中的操作符或者邻近操作符之间不可预料的相互作用
#define替换规则:
1.在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号,如果有,它们首先被替换
2.替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换
3.最后再次对文本进行扫描,看看它是否包含任何由#define定义的符号,如果有,则重复上述过程
注意:
1.宏参数和#define定义中可以出现其他#define定义的变量。但对于宏,不能出现递归
2.但预处理器搜索#define定义的符号时候,常量字符串的内容并不被搜索
#指令的使用:把一个宏参数变成对应的字符串
#define PRINT(X) printf("the value of "#X" is %d\n",X)
int main()
{
int a = 10;
int b = 20;
PRINT(a);
//printf("the value of""a"" is %d\n",a);
PRINT(b);
//printf("the value of""b"" is %d\n",b);
return 0;
}
##的作用:可以把位于它两边的符号合成一个符号。它允许宏定义从分离的文本片段创建标识符
属性 | #define定义宏 | 函数 |
代码长度 | 每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的长度会大幅度增长 | 函数代码只出现于一个地方,每次使用这个函数的时候,都调用同一个地方的同一份代码,没有扩充程序长度 |
执行速度 | 更快 | 存在函数的调用和返回的额外开销所以相对慢一点 |
操作符优先级 | 宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多加括号 | 函数参数只在函数调用的时候求值一次,它的结果值传递给函数。表达式的求值结果更容易预测 |
带有副作用的参数 | 参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果 | 函数参数只在传参的时候求值一次,结果更容易控制 |
参数类型 | 宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型 | 函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是不同的 |
调试 | 宏是不可以调试的 | 函数是可以逐语句调试的 |
递归 | 宏是不能递归的 | 函数是可以递归的 |
命名约定:把宏名全部大写,函数名不要全部大写