预处理和宏

预处理指令:

程序员所编写的代码不能被真正的编译器所编译,需要一段程序把代码翻译一下。
翻译的过程叫做预处理,执行翻译的程序叫做预处理器,被翻译的代码叫做预处理执行指令,以#开头的都是预处理
指令

查看预处理结果:

    gcc -E code.c   把预处理的结果直接显示到终端上
    gcc -E code.c -o code.i     把预处理的结果存储到.i结尾的文件中

预处理指令的分类

    #include 文件包含
        #include < >    从系统指定的目录下查找头文件并导入    
        #include " "    先从当前目录下查找头文件,如果找不到再从系统指定目录查找并导入
        注意:可以通过修改~/.bashrc 的环境变量来增加系统指定的目录
            export C_INCLUDE_PATH=$C_INCLUDE_PATH:路径  但不建议修改

#define 定义宏

宏常量:

define MAX 100
优点:提高可扩展性(批量性修改)、提高了安全性(常量)、提高可读性、可以与case配合使用
注意: 一般宏名全部大写,末尾不要加分号
一般局部变量全部小写用下划线分隔、全局变量首字母大写、函数名全部小写用下划线
分隔、宏名全部大写、指针变量+p、数组arr、字符串str

预定义的宏:

                __func__    获取函数名      %s
                __FILE__    获取文件名      %s
                __DATE__    获取当前日期    %s
                __TIME__    获取当前时间    %s
                __LINE__    获取当前行号    %d 
#include <stdio.h>

int main(int argc,const char* argv[])
{
	printf("%s\n",__func__);
	printf("%s\n",__FILE__);
	printf("%s\n",__DATE__);
	printf("%s\n",__TIME__);
	printf("%d\n",__LINE__);
}

在这里插入图片描述

宏函数:带参数的宏

            不是真正的函数,不检查参数的类型,没有传参,没有返回值,只有计算的结果
                #define SUM(a,b) a+b
                1、把代码中使用的宏函数替换为宏函数后面的代码   a+b
                2、把宏函数代码中使用的参数替换为调用者提供的参数
            
            注意:宏函数不能直接换行,如果需要换行要在末尾加续行符 \ 
                 宏函数也可以使用大括号来保护代码

宏的二义性:

            由于宏代码所处的位置、参数不同导致宏有不同的功能,这就叫做宏的二义性
            如何避免宏的二义性:
                宏函数整体加小括号、每个参数都要加小括号
                注意:使用宏函数时不要提供带自变运算符的变量作为参数(++或--)
                注意:容易出选择题: 例如哪个宏有二义性,一步一步替换宏函数
#include <stdio.h>

#define SUM(a,b) (a+b)
#define SUM1(a,b) (a*b)
#define SUM2(a,b) ((a)*(b)*(a))

#define swap(a,b) {a=b;\
b=a;\
a=b;\
b=a;\
a=b;\
b=a;}

int main(int argc,const char* argv[])
{
	int num1 = 10, num2 = 20;
	printf("%d\n",SUM(num1,num2)*10);
	printf("%d\n",SUM1(num1+10,num2)*10);
	printf("%d\n",SUM2(num1++,num2)*10);
	printf("%d\n",num1);

	swap(num1,num2);
}

在这里插入图片描述
在这里插入图片描述

    练习1:实现一个交换两个变量的宏函数,通用性
        #define swap(a,b) ...
#include <stdio.h>

//#define swap(a,b) {a=a+b;b=a-b;a=a-b;} //数据有溢出风险,不能交换结构类型
//#define swap(a,b) {a=a^b;b=a^b;a=a^b;}	//不能交换同一个变量,只能交换整形
//#define swap(a,b) {long double t=a;a=b;b=t;}//不能交换结构变量
//#define swap(a,b,type) {type t=a;a=b;b=t;}	//多一个参数
#define swap(a,b) {typeof(a) t=a;a=b;b=t;}	//typeof只能在gnu编译器使用

int main(int argc,const char* argv[])
{	
	int* num1, *num2;
	printf("%p %p\n",num1,num2);
	swap(num1,num2);
	printf("%p %p\n",num1,num2);
}

常见笔试面试题:

       1、#define 和 typedef 区别?
            如果是普通类型,它们的功能没有任何区别
            #define INT int
            typedef int INT
            
            如果是指针类型                
            #define INTP int*   
            typedef int* INT;   
            INTP p1,p2,p3;
            #define 只有p1是指针变量,p2 p3都是int类型变量
            typedef p1p2p3都是指针变量
 2、 宏函数与函数的区别?
            它们是什么?
                宏函数:不是真正的函数,只是代码替换,只是用法像函数
                函数:  一段具有某项功能的代码集合,会被编译成二进制指令,存储到代码段中,函数名就是该段内存的首地址、有独立的命名空间、栈空间

            有什么不一样?
            函数:  有返回值、类型检查、安全、入栈、出栈、速度慢、跳转
            宏函数:运算结果、 通用、   危险、替换、    、速度快、冗余,有二义性

条件编译

        根据条件让代码是否参与最终的编译

        版本控制
        #if
        #elif
        #else
        #endif
#include <stdio.h>

#define VERSON 1
int main(int argc,const char* argv[])
{
#if VERSON > 2
	printf("最新版本\n");
#elif VERSON > 1
	printf("还能用\n");
#else
	printf("该升级了\n");
#endif

}

在这里插入图片描述
只会编译符合条件的,节省时间,不符合的不参与编译

        头文件卫士:防止头文件被重复包含
        #ifndef
        #define
        #endif

        判断、调试、上线    gcc code.c -DDEBUG  -D 编译时定义宏
        #ifdef
        #else
        #endif
        
        定义打印调试信息的宏函数
        #ifdef DEBUG
            #define debug(...) printf(__VA_ARGS__)
        #else
            #define debug(...)
        #endif

        定义打印错误信息的宏函数
        #define error(...) printf("%s %s %s:%d:%m %s %s\n",__FILE__,__func__,__VA_ARGS__,__LINE__,__DATE__,__TIME__)

        注意:以上两个宏函数,能会使用即可

进入设置:vim ~/.vimrc

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值