预处理指令:
a.在编译前执行的指令
b.以 # 开头,句尾没有分号
c.主要分3种:宏定义、文件包含、条件编译
1.宏
记住一句话:宏纯粹是用来替换的
不带参数的宏定义
形式:
#define 宏名 值 把这行代码后所有的宏名替换为它的值 (字符串中的不会被替换)
宏名一般大写或者以字母k开头, 比如: #define kCount 4
宏定义定义常量
#define NUM 5 // 没有分号
代码...
#undef NUM
在编译(翻译成010101)之前把文件中这行代码之后的所有NUM替换为5 (直到文件结束或者到#undef)。
带参数的宏定义
形式
#define 宏名(参数) 参数表达式 编译时把宏替换为宏后面的表达式
比如 #define sum(a, b) a + b int a = sum(10, 10); // 相当于 int a = 10 + 10;
注意
宏定义是纯粹的字符串替换所以写宏定义时,要用括号把每个参数和整个表达式都括起来。像这样:
#define sum(a, b) ((a) + (b)) // 记得用括号!
比如如果用表达式作参数,假如我们定义了 #define mul(a,b) a * b, 然后用 int a = mul(1+2, 3+4) * 5 使用宏定义,它相当于 int a = 1 + 2 * 3 + 4 * 5= 37 而不是 3 * 7 * 5 = 105。
#define pingfang(a) ((a)*a)
int main()
{
int c = pingfang(5+5); // 替换之后就是(5+5)*5+5=55
NSLog(@"%d",c);
return 0;
}
带参数的宏定义和函数的区别 :
1 宏定义在编译前运算,函数在运行时运算,所以宏定义比函数更有效率(函数要在程序运行时进行运算,而这时宏定义在之前都运算完了),所以简单的函数,尽量用宏定义表示,提高效率。
2 没有运行检测(编译时会检测),只是纯粹的字符替换,所以自己要保证不要使用错了
3 没有参数和返回值的类型。
4 宏名不像函数名,不代表函数的地址,只能像上面那种方式使用。
宏定义的作用域
宏定义的位置可以在文件中的任意一行, 它的作用域从它所在那一行开始直到文件结束,或者到取消定义。
如果只需要在一段代码中使用宏定义,可以使用#undef来标记宏定义的结束,#undef之后的代码中的宏名不会被替换
#undef COUNT // 取消宏定义. 从这行开始, 后面不再替换COUNT.
/*
1.所有的宏以#开头,所以include是一个宏
2.预处理指令分三种
1宏定义
2条件编译
3文件包含 include
3.预处理指令执行在编译称0和1之前
4.预处理指令位置随便写
5.作用域:从指令那一行开始,到文件结束
6,宏名一般大写或者以k开头,变量名小写
*/
#import <Foundation/Foundation.h>
#define kCOUNT 4
int main()
{
int a[] = {1,23,4,5};
for (int i = 0;i<kCOUNT;i++)
{
NSLog(@"%d-",a[i]);
}
return 0;
}
#undef kCOUNT
2.条件编译
通常情况下,所有的代码都会被编译。但是有时我们希望程序中的一部分代码,只有在满足一定条件时才被编译和执行。
格式
#if 条件1
.... code ....
#else
.... code ....
#else
.... code ....
#endif // 一定要有 endif
条件判断
编译要用宏定义来做判断
#define NUM 10 // a > 0 这样是不可以的,因为编译前是不知道a的值的
#if NUM > 0
代码
#elif
代码
#else
代码
#endif
这样才是可以的,因为#define和#if都是预处理指令,编译前处理的
因为条件编译只编译部分的代码,所以效率更高。
其它用法:判断是否定义过某个宏
方法一: defined() 和 !defined()
#if defined(NUM)
code
#endif
如果定义过NUM这个宏(不看NUM的值),才编译这段代码
方法二: #ifdef 和 #ifndef
#ifndef NUM
code
#endif
如果没有定义NUM这个宏,才编译这段代码
3.文件包含
文件包含就是把一个文件的内容全部拷贝到这个文件中
#include < >
#include " "
前者会直接到C语言库函数头文件目录中寻找相应的文件;后者会先在源程序所在目录中寻找,如果没有,再到系统path里寻找,如果没有,再到库函数头文件目录里寻找
通常把C语言的库函数用<>包含,自己写的头文件用 " " 包含
注意
a.可以嵌套包含,不可以递归包含
嵌套包含:比如a.h包含(include)了b.h,b.h包含c.h,是可以的,import可以避免重复包含
递归包含:比如 a.h包含了b.h,b.h包含了a.h(相互包含),是不可以的,会报错
b.一个文件中如果多次包含同一个头文件,函数被重复声明,可以运行, 但是会降低编译效率。
如何避免多次包含同一个头文件
在自定义的头文件的前面,加上这么一段
#ifndef _NAME_ // 名字随意,但要保证不同头文件里面的名字不同,所以起名时最好根据文件名来起名
#define _NAME_
(#include a.h) // 有可能引用别的头文件
头文件中的声明
#endif