预处理指令:
程序员所编写的代码并不是标准c代码,不能被编译器真正编译,需要一段程序把代码翻译一下
翻译的程序叫做预处理器,翻译的过程叫做预处理,被翻译的语句叫做叫做预处理指令,以#开头的语句都是预处理指令
查看预处理结果:
gcc -E xxx.c 把预处理的结果显示到终端
gcc -E xxx.c -o xxx.i 把预处理的结果存储到.i预处理文件中
预处理指令的分类:
#include 导入头文件
#include <> 从系统指定的路径下查找并导入头文件
#include "" 先从当前路径下查找头文件,如果找不到,再从系统指定的路径下查找并导入头文件
编译参数 -I /path 也可以指定头文件查找路径
系统通过设置环境变量的方式来指定头文件的系统查找方式
#define 定义宏
宏常量
#define MAX 50
优点:提高可读性、提高可扩展性,方便批量修改、提高安全性,还可以与case配合使用
注意:建议宏常量名全部大写,末尾不要加分号
【函数名、局部变量 小写+下划线】
【全局变量 首字母大写】
【指针变量 +p】
【数组 arr】
【字符串 str】
注意:typedef int num; 用法和含义上的区别
预定义好的宏常量:
__func__ 获取函数名
__FILE__ 获取文件名
__LINE__ 获取行号
__DATE__ 获取日期
__TIME__ 获取时间
宏函数
#define SUM(a,b) a+b
宏函数其实就是是带参数的宏
宏函数不是真正的函数,不检查参数类型,没有传参,没有返回值,只有替换后的运算结果
如何实现:
1、把代码中使用到宏函数的地方替换为宏函数后面的代码
2、把宏函数代码中使用的参数替换为调用者提供的参数
宏的二义性:
由于宏位置的不同、参数的不同导致宏有不同的功能
如何避免宏的二义性
1、宏函数整体加小括号
2、每个参数都加小括号
注意:在使用宏函数时,不要提供带自变运算符的变量作为参数
注意:容易出现选择题,直接问哪个有二义性,提供宏函数问宏函数的结果
注意:宏函数可以用大括号保护代码,宏定义常量、宏函数时不能换行,但是可以在一行的末尾使用续航符 \ 换行
常考的笔试面试题:
#define 和 typedef 有什么区别?
#define 是宏定义
typedef 是类型重定义
如果是普通类型时,没有任何的区别
#define TNT int
typedef int TNT;
TNT num;
指针类型有区别:
#define TNTP int*
TNTP p1,p2,p3; //p1是指针 p2p3是int类型
typedef int* TNTP;
TNTP p1,p2,p3; //p1,p2,p3都是指针
2、sizeof和strlen有什么区别?
sizeof是一个计算变量、类型的字节数的运算符
strlen是一个函数,计算字符串的长度
3、宏函数与普通函数有什么区别?
宏函数:带参数的宏替换,不是真正的函数,只是用起来像函数而已
函数:一段具有某项功能的代码的集合,会被编译成二进制指令存储在代码段中,函数名就是该段代码的首地址,有独立的栈内存、命名空间
有什么不同?
函数:返回值 参数类型检查 安全性更高 传参 速度慢 跳转
宏函数:运算结果 通用 相对危险 替换 速度快 代码冗余
条件编译:
根据条件决定让哪些代码参与编译,哪些代码不参与编译
版本控制:
#if
#elif
#else
#endif
注意:还可以使用#if 0 #endif 注释整段代码
头文件卫士:防止头文件重复包含
#ifndef 宏名(头文件名大写)
#define 宏名
#endif//宏名
判断、调试代码:
#ifdef 宏名
#else
#endif
注意:可以在gcc 编译时通过参数 -D宏名 为此次编译的结果添加宏
调试代码
#ifdef DEBUG
#define DEBUG(...) printf(__VA_ARGS__)
#else
#define DEBUG(...)
#endif
提示错误信息
#define error(...) printf("%s %s :%d %s %m %s %s\n",__FILE__,__func__,__LIN E__,__VA_ARGS__,__DATE__,__TIME__)
作业:实现一个交换两个变量的宏函数,多少种写法,那种最通用

被折叠的 条评论
为什么被折叠?



