目录
1. 预定义符号
VS:不支持STDC,VS并没有完全遵守C语言标准,所以有时候会出现莫名其妙的bug
代码展示:
主要记住对应的打印格式,例如时间是%s打印,行号是%d打印等等
FUNCTION是打印当前代码的函数
简单的使用,写日志文件:
2. 预处理指令
所有 # 开头的指令都是预处理指令
3 #define
#define------>预处理指令,不是关键字
3.1 #define定义符号
不带参数的
#define 后面不要加分号(;)
- 虽然加了有的时候也没错,只是简单的替换,多了一个空语句而已
- 但是有的时候,多加一个分号(;),会导致程序错误
例如:
#define MAX 100;
printf("%d\n",MAX);----------->printf("%d\n",100;);❌
3.2 #difine定义宏
带有参数的
宏名全部大写,参数也大写
定义的格式:
例如1:
宏只是完成替换:5+1*5+1=11 没有达到预期的结果,更改后
例如2:
宏只是完成替换:10*5+5=55 没有达到预期的结果,更改后
定义宏的时候,建议将参数加上括号,防止运算错误
#define ADD(X) ((X)+(X)) // 写宏的时候不要吝啬括号
3.2.1 #define的替换规则
需要注意的是:
字符串里面的MAX不被替换:
3.2.2 #和##
#X
把X的参数转换为"X"字符串
例如:
问题:
函数实现不了,使用宏来完成
额外知识:
使用宏完成功能:
##
3.2.3 带副作用的宏参数
宏只是简单的替换,不会计算
解析:
宏完成的替换
a++先使用在++,a是10,b是11,所以判断为假,进入后面的(b++)
但是这时候a,b已经++过了,此时a=11,b=12
b++是先使用在++,所以
max = 12
a = 11
b = 13
3.2.4 宏和函数的比较
这道题如果二选一的话,宏的效果好一点
宏的缺点:
宏不能被函数替换的作用:
宏可以传类型,函数只能传递类型对应的值
3.2.5 #undef 移除一条宏定义
4. 条件编译
如果定义了DEGUB,就执行打印,没有就不执行
定义DEBUG的时候,有没有值都可以,0也可以
只有定义就行,没有真假区别
#ifdef 要和 #endif 一起使用
0 为假,不编译
非0为真,执行编译
5. 头文件包含
- 双引号"" : 本地文件
先在源文件目录查找
然后去VS安装目录查找
- <> : 库文件,
只会去VS的安装目录查找
5.1 关于头文件重复包含
1.#ifndef
#ifndef __ADD_H__ // 如果没有定义add.h,没有包含,条件为真;包含的话,条件为假,跳过
#define __ADD_H__ // 定义一下add.h头文件
int Add(int,int); // 函数声明,不是函数定义
#endif // 结束条件编译
2.#pragma once
防止头文件被重复引用,库文件都是这样写的,可以自己打开查看
5.2 头文件的打开
如果需要查看库头文件,只需要右键-->打开文档就行
如果需要查看库函数,只需要右键-->查看定义就行
- 有的库函数,必须引头文件才能使用
- 库函数的tab 提示,需要包含头文件
- 打开文档或者查看库函数定义,都需要#include头文件
查看头文件的路径:
查看库头文件,只需要右键-->打开文档就行
然后,右键打开文件所在文件夹
6. 利用宏,计算结构体成员的偏移地址(offsetof)
定义宏模拟实现offsetof:
将0强制转换成struct S的地址
那么对应的成员变量的地址就是偏移地址
将地址转换为int类型