黑马程序员--04C预处理
来源:互联网 发布:vscode 导出配置 编辑:程序博客网 时间:2024/06/05 17:56
预处理指令:
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 4int 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
- 黑马程序员--04C预处理
- 黑马程序员-C语言预处理
- 黑马程序员---C语言预处理
- 黑马程序员 C语言------预处理指令学习
- 15、黑马程序员-C语言预处理指令
- [黑马程序员][C语言]预处理指令
- 黑马程序员---【C语言】06预处理命令
- 黑马程序员----C语言预处理篇
- 黑马程序员-C语言基础知识-预处理
- 黑马程序员-----------C语言基础-----------预处理指令
- 黑马程序员--ios基础--c语言--预处理指令、typedef、static和extern、递归
- 黑马程序员-预处理
- 黑马程序员-预处理指令
- 黑马程序员....................预处理指令
- 黑马程序员—C语言_预处理指令
- 黑马程序员-IOS-C语言预处理指令及杂项小计
- 黑马程序员——C语言之预处理命令
- 黑马程序员 C语言 - 09 预处理指令、typedef、extern、static
- H2数据库攻略之三-结合Maven
- Wince stepldr代码解析
- 欢迎使用CSDN-markdown编辑器
- CSS规范
- Android 插件化技术 加载任意未安装apk
- 黑马程序员--04C预处理
- NYOJ 374 弹球II
- 1075. PAT Judge (25)
- POJ 题目3723 Conscription(最小生成树变形)
- typedef void (^funcblock)(void);
- iOS 模糊搜索
- [Codeforces #295(Div 2)]简要题解
- gradle多渠道打包及友盟统计-eclipse版本
- 1076. Forwards on Weibo (30)