第三周总结03

一、预处理指令


程序员所编写的代码不能被真正的编译器所编译,需要先经过一段程序翻译一下

翻译的过程称为预处理,负责翻译的程序称为预处理器,被翻译的语句叫做预处理指令,以#开头的都是预处理指令

查看预处理结果:

gcc -E code.c 把预处理的结果显示到终端

gcc -E code.c -o code.i 把预处理的结果存储到.i预处理文件

二、预处理指令的分类


#include 头文件导入(拷贝)

通过设置环境变量来制定路径

#define 定义宏
宏常量:
#define MAX 50

优点:提高代码可扩展性、提高可读性、提高安全性、还可以与case配合

预定义好的宏常量:

__ func __:获取函数名

__ FILE __:获取文件名

__ LINE __:获取行号

__ DATE __:获取日期

__ TIME __:获取时间

注意:定义宏常量不要加 分号

一般宏名全部大写

宏函数:

是带参数的宏

不是真正意义上的函数,没有发生传参,没有返回值,不会去检查参数的类型

普通函数:一段具有某项功能的代码集合,会被编译成二进制指令存储在代码段中,函数名就是它的首地址,有独立的栈内存

宏函数:带参数的宏替换,不是真正的函数,用起来像函数,没有独立的栈内存

#define SUM(a,b) a+b
// 作用:1、先把代码中出现了宏函数的位置,替换成宏函数后面的语句
//      2、再把代码中使用的参数替换成调用者的参数

#define 与 typedef 的区别

#define INT int
typedef int INT      
// 一个是代码替换,一个是类型重定义  

如果是普通类型,它们在功能上无任何区别,但本质不同。

#define INTP int*
INTP p1,p2,p3;    //p1是指针,p2,p3是int
typedef int* INTP
INTP p1,p2,p3;    // p1,p2,p3都是指针

注意:宏的内容必须保证在同一行,如果要换行,要在每一行的末尾添加续航符 \

宏函数的二义性:

由于宏函数代码位置、附近的值、参数等各种原因的影响,会导致宏函数有不同的解释,这叫做宏的二义性

如何避免宏的二义性:

每个参数都加小括号,整体也加小括号,不要在宏函数的参数中使用自变运算符

三、条件编译


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

版本控制:

#if

#elif

#else

#endif

#include <stdio.h>

#define VERSION 3
int main()
{
//#if 0
#if VERSION > 2
    printf("\n");
#elif VERSION > 1
    printf("\n");
#else
    printf("\n");
#endif
//#endif
}
头文件卫士:

防止头文件被重复包含,头文件必加

#ifndef 宏名(头文件名大写_H) // 如果宏名不存在为真

#define 宏名(头文件名大写_H)

//

#endif//头文件名大写_H

判断、调试:

#ifdef 宏名// 如果宏名存在为真

#else

#endif

在编译时添加宏DEBUG:gcc 程序名.c -DDEBUG

#include <stdio.h>

// 打印调试信息
#ifdef DEBUG
    #define debug(...) printf(__VA_AGRS__)
#else
    #define debug(...)
#endif
// 打印错误信息
#define error(...) printf("%s\n %s:%d\n %s %m\n %s %s\n",__FILE__,__func__,\
                           __LINE__,__VA_ARGS__,__DATE__,__TIME__)

int main()
{
    
    int num = 0;
    int ret = scanf("%d",&num);
    debug("ret=%d\n",num);
     
    
    
    FILE* fp = fopen("a.out","r");
    if(NULL == fp)
    {
        error("fopen");
        return 0;
    }
    printf("Success\n");
    return 0;
}

四、头文件中应该写什么


头文件可能会被任意源文件包含,意味着头文件中的内容可能会在多个目标文件中存在,要保证合并时不要冲突

重点:头文件只编写声明语句不能有定义语句

全局变量声明

函数声明

宏常量

宏函数

typedef 类型重定义

结构、枚举、联合的类型设计声明

头文件的编写规则:

1、为每个 .c 文件写一份 .h 文件,.h 文件是对它对应的 .c 文件的说明

2、如果需要用到某个 .c 文件中的变量、函数、宏时,只需要把该文件的.h文件导入即可

3、.c 文件也要导入自己的 .h 文件,目的是为了让定义与声明保持一致

头文件的相互包含:

假如 a.h包含了 b.h 的内容,而 b.h 中又包含了 a.h 的内容,这时就会产生头文件的相互包含,无法编译通过

解决方案:把 a.h 中需要 b.h 的内容,和 b.h 中需要 a.h 的内容提取出来,额外再写另一个 c.h

五、Makefile:


Makefile 是由一系列的编译器指令组成的可执行文件,叫做编译脚本

在终端执行 make 命令就会自动执行 Makefile 脚本中的编译指令,它可以根据文件的修改时间和依赖关系来判断哪些文件需要编译,哪些不需要编译

需要一个名字叫做 Makefile 文件

Makefile的编译规则:

1、如果这个工程没有编译过,那么我们的所有 c 文件都要编译并链接

2、如果这个工程的某几个 c 文件被修改,那么我们只编译被修改的 c 文件,并重新链接目标程序

3、如果这个工程的有文件被更改了,那么引用了这几个头文件的 c 文件都会重新编译,并链接目标程序

一个最简单的Makefile脚本格式:

执行目标:依赖

编译指令

被依赖的目标1:依赖的文件

编译指令

被依赖的目标2:依赖的文件

编译指令

......

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值