1.#运算符
#运算符将宏的一个参数转换为字符串字面量。它仅允许出现在带参数的宏的替换列表中。
#运算符所执行的操作可以理解为”字符串化“。
例如:
我们将打印的字符串中的n改为参数n,这样在传参的时候就也会随着变化。假如我们不将其改为参数n的话会发生什么呢?我们来看看:
我们发现没有改变,注意在将其改为参数n时不要忘记了“”,因为这样引起来它们就是一个字符串。
2.命名约定
一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。
那我们平时的一个习惯是:
1.把宏名全部大写
2.函数名不要全部大写
3.#undef
这条指令用于移除一个宏定义。如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。比如之前写的ADD要重新定义的话就是:
4. 命令行定义
许多C的编译器提供了一种能力,允许在命令行中定义符号。用于启动编译过程。
例如:当我们根据同一个源文件要编译出一个程序的不同版本的时候,这个特性有点用处。(假定某个程序中声明了一个某个长度的数组,如果机器内存有限,我们需要一个很小的数组,但是另外一个机器内存大些,我们需要一个数组能够大些。)
5.条件编译
在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件编译指令。
在 C 语言中,一个文件中可以包含多个头文件,而头文件之间又是可以相互引用的,这将引起一个文件中可能间接多次包含某个头文件,从而导致了某些头文件被重复引用多次。某些头文件重复引用只是增加了编译器编译的工作量,导致编译效率降低,不会引起太大的问题。但是,这里还需要说明的是,对比较大的工程而言,编译效率低下也将是一件非常痛苦的事情。某些头文件重复引用,有可能会引起意想不到的严重错误。比如,在头文件中定义了全局变量(虽然这种方式不被推荐,但有时候确实需要这么做),将会导致全局变量被重复定义。
在 C 语言中,避免同一个头文件被多次包含、重复引用,最常用也是最简单的方法就是利用“#ifndef/#define/#endif”结构产生预处理块来防止头文件被重复引用。如下面的示例代码所示:
#ifndef __HEADERNAME_H__
#define __HEADERNAME_H__
/*声明、定义语句*/
#endif
在上面的预处理块中,当第一次引用(include)头文件时,由于“__HEADERNAME_H__”还没有被宏定义(define)过,即满足“#ifndef__HEADERNAME_H__”,从而执行“#define__HEADERNAME_H__”以及其他内容。
如果因为编码者的不小心或者嵌套包含等原因造成了这个头文件被多次引用(include),那么“#ifndef__HEADERNAME_H__”判断条件将在第二次引用(include)头文件时得不到满足,因此不执行后面的内容,直接跳到“#endif”。
当然有#ifndef就有#ifdef它的作用刚好相反,如果定义了就执行下面语句,没有就不执行。
6.头文件包含
我们自己创建的头文件就叫本地头文件,我们使用的时候就是#include"add.h"等.
库文件包含就是#include<stdio.h>等。它们之间有什么区别吗?其实“”包含头文件时先在源文件所在目录下查找,找不到再去标准头文件路径中去找寻,而<>是直接去标准头文件路径中去找寻。虽然“”不但可以去源文件所在目录下找寻,也可以去标准头文件路径下去查找,那为啥不都用“”包含呢?虽然可以都使用“”进行包含,但是这样做查找的效率就低些,当然这样也不容易区分是库文件还是本地文件了。
7. 嵌套文件包含
我们已经知道, #include 指令可以使另外一个文件被编译。就像它实际出现于 #include 指令的
地方一样。
这种替换的方式很简单:预处理器先删除这条指令,并用包含文件的内容替换。
⼀个头文件被包含10次,那就实际被编译10次,如果重复包含,对编译的压力就比较大。
如果工程比较大,有公共使用的头文件,被大家都能使用,又不做任何的处理,那么后果真的不堪设想。
解决方法:条件编译或#pragma once(此头文件只会被包含一次)