前言
之前在编码方向的学习都是在非常方便的编译器上进行的,直到一次gcc -v -o我才了解到编译器在我们写完代码之后做了非常多的事情,了解了这些之后也让我对之前很多的错误理解的更加通透,希望下面对编译器的介绍能给新手们一点指导(下面以c语言展开)
一、基本的编译步骤
cc1 .c -------> DNZ4.s 普通语言------编译(操作)------汇编语言
as DNZ4.s-------->BW16.o 汇编语言-------汇编(操作)-------机器指令集
collect2 *.o(有好多)--------> .exe 机器指令集--------链接 确定数据地址---------可执行文件
这三步里先阶段我们的错误大部分是在第一步,也就是语法错误,但随着学习的深入我们在第三步也是会出现错误的。
二、预编译
在编译器编译代码之前,类似printf这种关键字其实编译器是不认识的,这时候我们一般都是引用头文件去让编译器“学习”到这些关键字,预处理的符号就是#,就是在编译之前让编译器提前学习到一些关键字,这里分为头文件和宏的预处理。
通过控制台对文件实现预处理之后,可以发现产生了一个 .i 的文件,文件里面已经用define定义的宏值替换代码里的宏名。
我觉得非常变态的面试题:以下写法是否正确?
int define
一般关键字是不能拿来当变量名的,但是include,define这种必须要变成#define,#include才算是关键字,所以以上的写法是正确的!
以上的预处理指令新手平时见到的会非常多,下面的条件编译对于我这种非科班来说之前是未了解过的,但是在了解了这样的方法之后感觉真的是太方便了,有一种相见恨晚的感觉。
下面我们模拟一个场景,开发过程中我们为了调试,printf了很多数据来监测后台数据,但是产品发布的时候我们要尽量的缩小运行内存,不让这些printf执行,按照我之前的习惯就是一句一句把printf注销掉,但其实我们可以通过预处理很好的解决这个问题。
这句话的意思是,如果我们定义过DEBUG那我们if判断成功,未定义过则进入else里的语句。
这时候我们如果想检测后台数据,可以直接在代码上加一个#define DEBUG来触发if条件,不过这不是最好的方法(动了别人的代码),最好的办法是在编译上面做操作,这时候我们不要直接使用编译器给的默认的编译,cmd打开命令提示符面板,在编译语句前的--中间插入D加上你ifdefine后面的符号(D跟后面的符号是紧挨的),像如上我就应该写成 -DDEBUG -,如果这个.c文件叫a.c的话编译语句就是如下的。
总结
了解编译器的编译流程能在以后解决问题的时候有更多的思路,也能对之前的问题有更好的理解,预处理的很多操作给我写项目的时候带来了极大的便利,慢慢了解自己使用的工具也是学习非常重要的一部分。