C++知识点复习(面向面试7)
我们开始今天的复习31.C生成可执行文件的四个步骤32.什么是悬挂指针33.什么时候会出现悬挂指针34.#define和const有什么区别35.include 和include 的区别好的我们从第31条开始。31.C生成可执行文件的四个步骤 预处理Preprocessing核心任务纯文本替换与展开。具体动作处理#include把头文件如iostream的内容完整地拷贝到源文件中。处理#define把代码中所有的宏比如#define PI 3.14替换成具体的值。处理条件编译根据#ifdef、#if等指令决定保留或剔除哪些代码。去除注释把代码里写的注释全部删掉。产出物生成一个后缀为.i的预处理文件依然是纯文本但代码量会因为头文件展开变得非常大。⚙️ 编译Compilation核心任务将高级语言翻译成汇编语言。具体动作这是编译器真正开始“理解”代码的阶段。它会进行词法分析、语法分析、语义分析比如检查你有没有把字符串赋值给整型变量。如果发现语法错误就会在这一步报错并终止。确认代码无误后将其翻译成特定 CPU 架构如 x86 或 ARM的汇编指令。产出物生成一个后缀为.s的汇编代码文件依然是人类可读的文本。 汇编Assembly核心任务将汇编语言翻译成机器语言二进制。具体动作汇编器Assembler把.s文件里的每一条汇编指令逐行翻译成 CPU 能直接识别的 0 和 1机器码。此时会生成“目标文件”Object File里面包含了二进制机器码以及符号表记录了函数名、全局变量名等信息但此时它们的内存地址还是临时的。产出物生成一个后缀为.oLinux/Unix或.objWindows的目标文件已经是二进制人类不可读。 链接Linking核心任务拼积木生成最终可执行文件。具体动作符号解析如果你在main.cpp里调用了printf或者另一个文件里的函数链接器会负责找到这些函数的具体定义在哪里。地址重定位把各个目标文件中函数的临时地址替换成程序运行时的真实内存地址。合并库文件把你用到的标准库比如iostream相关的库或者第三方库合并进来。产出物生成最终的可执行文件如 Linux 下的a.out或 Windows 下的.exe。 实战中的命令对应以 Linux g 为例在实际开发中我们通常一条命令就搞定了比如g main.cpp -o app但编译器内部其实默默按顺序执行了上述四步。如果你想手动拆解体验一下可以使用以下命令预处理g -E main.cpp -o main.i编译g -S main.i -o main.s汇编g -c main.s -o main.o链接g main.o -o app32.什么是悬挂指针悬挂指针也叫野指针是指指向非法内存地址的指针即无法正常使用的指针。33.什么时候会出现悬挂指针●使用未初始化的指针在定义指针变量后没有对其进行初始化这是出现悬挂指针最典型的情形。●指针所指的对象已经消亡当指针指向的对象的生命周期结束后对象已经消亡但仍然使用该指针访问该对象就会出现运行时错误。●指针释放后未置空指针被free或者delete释放后没有置为NULL此时指针指向的是“垃圾”内存。●在C语言中realloc函数使用不当如果原内存后面没有足够的空间来将原有空间扩展成一个连续的新大小realloc函数会从堆中重新找一块新内存并把原来通过malloc函数得到的内存空间中的内容复制到这块新内存中此时数据发生了移动那么原指针所指向的内存空间实际上已经被释放这样就会产生原指针的悬挂。34.#define和const有什么区别●define定义的常量没有类型const定义的常量有类型的名字●编译器对其处理不同define定义的宏在预处理阶段被替换可能有多个拷贝const定义的变量在编译时确定值只有一个拷贝为什么会有一个拷贝参考const修饰的变量能被修改cast_const()35.include 和include 的区别●#include 用于包含系统标准头文件。编译器会在系统指定的标准头文件目录中查找要包含的头文件。例如iostream等。●#include 通常用于包含用户自己编写的头文件。编译器会先在当前源文件所在目录查找。