1、翻译程序的第一步
(1)把源代码中出现的自符映射到源字符集
(2)编译器查找反斜线后紧跟换行符的实例并删除这些实例
注:“换行符”代表按下回车键在源代码文件中新起一行所产生的字符,而不是 ‘\n’代表的字符
预处理表达式的长度为一个逻辑行,一个逻辑行可能比一个物理行多
(3)编译器将文本划分成预处理的语言符号序列、空白字符、注释序列
注:编译器会用一个空格字符代替每一个注释
2、明显常量 #define
#define行(即逻辑行)由三部分组成:
指令#define本身
宏:分为类对象宏、类函数宏
宏的命名规则:和变脸一样,第一个字符不能为数字
替换列表/主体
3、在类函数宏中要注意括号的添加
4、希望在字符串中包含宏参数,使用预处理运算符#,它可以把语言符号转化为字符串,这个过程叫字符串化
#define PSQR(x) printf("the square of "#x" is %d\n", ((x) * (x)))
这样打印打出来的就是 x 字符串
5、##运算符--粘合
可用于类函数宏的替换部分,也可用于类对象宏的替换部分
6、可变宏:
... 和 __VA_ARGS__(用在替换部分)
#define PR(...) printf(__VA_ARGS__)
7、既然类函数宏和函数很相似,应怎么取舍呢
(1)宏在某种程度上比常规的函数复杂
(2)宏宇函数见的选择实际上是时间与空间的权衡;宏产生的是内联代码,每调用一次及ucharu一次,浪费空间,而程序中的函数是指拷贝一份,节省空间,但程序的控制必须转移到函数中并随后返回条用程序,因此比内联代码花费的时间多
8、使用宏的注意事项:
宏的名字中不能有空格,但是在替代字符串中可以有
要用圆括号括住每个参数,并括住宏的整体定义
使用大写字母表示宏名,这是习惯
9、可以使用头文件来声明多个头文件共享的外部变量,如,
int s = 0; //文件作用域,源代码文件中
接着,在于源代码文件相关的头文件中进行引用声明:
extern int s;//头文件中
这样只要包含了这个头文件,就能使用这个变量
如果在定义变量的时候加上 static后,每个包含改头文件的文件都获得一份该常量的副本
10、#undef指令
取消定义一个给定的#define
即使你取消了一个前面没有定义的宏也是合法的; 如果你在使用某个名字之前不确定前面是否有人用过,为了安全起见,应先取消一下
11、条件编译:
#ifdef、#else、#endif:
用于选择编译模块
#ifndef、#endif:
经常使用#ifndef防止对该宏重复定义
#if、#elif、#else、#endif
后跟常量整数表达式,如果表达式为非零值,则表达式为真
12、预定义宏
__DATE__ 进行预处理的时间
__FILE__ 当前源代码文件名
__LINE__ 当前源代码的行号
__TIME__ 源文件的编译时间
__func__ 当前执行函数的函数名
13、#line、#error
#line:重置由__LINE__和__FILE__宏报告的行号和文件名
#line 10 "cool.c" //把行号重置为10,文件名重置为cool.c
#error:使预处理器发出一条错误消息
14、#pragme
将编译器指令置于源代码中
15、内联函数:
创建内联函数的方法:在函数声明中使用函数说明符 inline
编译器看到内联声明后会用函数体代替函数调用
内联函数不会再调试器中显示
内联函数应该比较短小
内联函数的定义和对该函数的调用必须在同一个文件中,正因为这样,内联函数通常具有内部链接
通常用法:在头文件中定义内联函数,并在使用该函数的文件中包含中包含该头文件