预处理指令
在编译和链接之前,还需要对源文件进行一些文本方面的操作,比如文本替换、文件包含、删除部分代码等,这个过程叫做预处理。
常见的预处理指令#include、#define...等,预处理主要处理以#开头的命令,例如#include <stdio.h>,预处理命令放在所有函数之外,一般放在源文件的前面。
- 在代码编译之前的指令,预处理的三种方式,
宏定义 、文件包含、条件编译 - 预处理指令的作用域: 从代码编写指令的那一行开始到文件的结尾
宏定义
#define 叫做宏定义命令,所谓宏定义,就是用一个标识符来表示一个字符串,如果在宏定义之后的代码中出现了对应的标识符,那么就全部替换成指定的字符串。注意:宏定义只是起到替换作用,宏定义的作用域在定义宏#define和取消宏#undef之间,宏定义允许嵌套使用。
- 不带参数的宏定义
c
//宏名默认大写或者以k开头
#define COUNT 6
//取消定义,宏定义到这里失效
#undef COUNT1
2
3
4
5
2
3
4
5
- 带参数的宏定义
c
// 宏定义传参时要注意,每个参数和结构都要用一个小括号(),防止传的值有问题影响计算结果,因为宏仅仅只有替换作用。注意宏名和形参列表之间不能有空格
#define sum(v1,v2) ((v1)+(v2))
// 为什么使用括号,如果使用下面的宏定义,100/sum(1,2),展示之后是100/1+2
#define sum(v1,v2) (v1)+(v2)1
2
3
4
2
3
4
- 宏参数转换为字符串
#
c
// 如果参数前有#号,宏会自动在参数上加上"",注意返回的是一个char*类型
#define file(path) "123"#path
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"%@ ---", [NSString stringWithUTF8String:file(456)]);
NSLog(@"%@ ---", [NSString stringWithUTF8String:file("456")]);
}
return 0;
}
打印结果: 123456
123"456"1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- 连接符
##,将宏参数或其他的串连接起来
c
#define COUNT(path) 123##456##path
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"%d --",COUNT(789));
}
return 0;
}
打印结果: 1234567891
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 多行宏定义使用
\进行连接
c
// 当宏定义一行写不下的时候,可以使用\进行换行,\后不能有空格
#define Log NSLog(@"%d--",__LINE__);\
NSLog(@"%s--","a");\
NSLog(@"%s--","b");1
2
3
4
2
3
4
ANSI C 规定了以下几个预定义宏,它们在各个编译器下都可以使用:
宏定义 含义 __LINE__表示当前源代码的行号; __FILE__表示当前源文件的名称; __DATE__表示当前的编译日期; __TIME__表示当前的编译时间; __STDC__当要求程序严格遵循 ANSI C 标准时该标识被赋值为 1; __cplusplus当编写 C++程序时该标识符被定义。 __func__编译器中的宏,值为调用__func__函数的函数名。
条件编译
顾明思议:满足特定的条件才进行编译,有三种形式 #ifdef、 #ifndef、#if
#ifdef:如果有宏定义,执行对应的代码段,没有定义,执行另一个代码段
c
#ifdef 宏名 // 如果当前的宏有定义,执行代码段1
程序段1
#else // 当前的宏没有定义执行代码段2
程序段2
#endif1
2
3
4
5
2
3
4
5
#ifndef:如果没有定义宏,则执行对应代码段
c
#ifndef 宏名 // 如果当前的宏没有定义,执行代码段1
程序段1
#else // 如果有定义宏,执行代码段2
程序段2
#endif1
2
3
4
5
2
3
4
5
#if: ... #elif ... #else ....#endif满足对应的条件执行对应的代码块
c
#if 条件1
代码段1
#elif 条件2
代码段2
#else
代码段3
#endif1
2
3
4
5
6
7
2
3
4
5
6
7
文件包含 #include
#include的本质是拷贝另一个文件的内容到当前的位置
- #include <文件名>: 编译器将在系统设定的标准目录下搜索该文件
- #include "文件名" : 编译器首先在当前目录中查找该文件,如果没有找到,再到系统设定的目录下查找
在实际开发中,为了保证.h文件不被多次应用,一般都会使用#ifndef + __文件名_H_做一个宏定义
c
#ifndef _STDIO_H_
#define _STDIO_H_
文件中的内容
#endif1
2
3
4
2
3
4
#error 阻止程序编译
#error 指令用于在编译期间产生错误信息,并阻止程序的编译,比如当我们希望以 C++ 的方式来编译程序时,可以这样做:
c
#ifndef __cplusplus
#error 当前程序必须以 C++方式编译
#endif1
2
3
2
3
预处理指令总结
| 指令 | 说明 |
|---|---|
# | 空指令,无任何效果 |
#include | 包含一个源代码文件 |
#define | 定义宏 |
#undef | 取消已定义的宏 |
#if | 如果给定条件为真,则编译下面代码 |
#ifdef | 如果宏已经定义,则编译下面代码 |
#ifndef | 如果宏没有定义,则编译下面代码 |
#elif | 如果前面的#if 条件不为真,当前条件为真,则编译下面代码 |
#endif | 结束一个#if……#else 条件编译块 |