C/C++八股面试题(六)
目录:
1.请你说说动态链接与静态链接两者有什么区别?
2.请简单说说静态成员函数与普通成员函数的区别?
3.简述C++从代码到可执行二进制文件的过程?
4.全局变量和局部变量的区别?
5.C语言的基本类型有哪些(32位系统),占用字节空间?
6.头文件#ifndef/#define/#endif的作用?
内容:
1.请你说说动态链接与静态链接两者有什么区别?
动态链接的基本思想:
- 是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序。
动态链接
- 从链接时机看:动态链接是在程序运行时完成的,即程序在运行时加载外部的共享库(如
.dll
、.so
文件)。 - 从文件大小看:生成的可执行文件较小,因为它只包含调用库的引用,而不包含库的实际代码。
- 从性能看:动态链接可能会略微影响程序启动速度,因为需要在运行时加载和解析库文件。
- 从依赖上看:程序在运行时依赖外部的动态库,如果系统中缺少这些库或版本不匹配,程序可能无法正常启动或运行。动态链接的好处是库的更新不需要重新编译应用程序,只要保持接口一致即可。
静态链接的基本思想:
- 我们不可能将所有代码放在一个源文件中,所以会出现多个源文件,而且多个源文件之间不是独立的,而会存在多种依赖关系,如一个源文件可能要调用另一个源文件中定义的函数,但是每个源文件都是独立编译的,即每个.c文件会形成一个.o文件,所以就会有依赖关系,则需要将这些源文件产生的目标文件进行链接,从而形成一个可以执行的程序。这个链接的过程就是静态链接。
静态链接
- 从链接时机看:静态链接在编译阶段完成,生成的可执行文件中包含了所有依赖库的代码和符号表。
- 从文件大小看:生成的可执行文件相对较大,因为它包括了所有依赖的库文件。
- 从性能看:由于库的代码已经被直接包含在可执行文件中,因此程序的加载速度较快,运行时不需要查找和加载外部库。
- 从依赖上看:程序在运行时不依赖外部的库文件,减少了运行时出现版本不兼容的问题。但如果库有更新,程序需要重新编译。
总结对比
链接时机 |
编译时 |
运行时 |
可执行文件大小 |
较大 |
较小 |
启动速度 |
较快 |
较慢(需要加载共享库) |
依赖管理 |
运行时不依赖外部库 |
运行时依赖外部库 |
库更新 |
库更新需要重新编译程序 |
库更新无需重新编译程序 |
共享性 |
每个程序都有独立的库副本 |
多个程序可以共享相同的库 |
2.请简单说说静态成员函数与普通成员函数的区别?
访问对象
- 普通成员函数:普通成员函数是与类的实例(对象)关联的函数。它必须通过对象来调用,并且在函数内部可以访问该对象的所有成员变量和成员函数。在成员函数内部,可以使用
this
指针来访问对象的成员变量。obj.func()
这种调用可以理解为:myClass::func(&obj)
- 静态成员函数:静态成员函数是与类本身关联的,而不是与类的某个具体对象关联。它可以直接通过类名来调用,不需要先创建对象。
访问成员变量
- 普通成员函数:可以访问类的所有成员,包括静态成员和非静态成员包括私有成员。
- 静态成员函数:只能访问静态成员变量和静态成员函数。它不能访问非静态成员变量和非静态成员函数,因为静态成员函数在类的实例化对象未创建时就已经存在,它无法指向某个具体对象。
this
指针
- 普通成员函数:每个普通成员函数都有一个隐式的
this
指针,指向当前调用该成员函数的对象。通过this
指针,可以访问对象的成员变量和成员函数。 - 静态成员函数:静态成员函数没有
this
指针,因为它不是与某个对象关联的。因此,静态成员函数无法通过this
指针来访问成员变量和成员函数。
调用方式
- 普通成员函数:必须通过类的对象来调用,或者通过指针/引用访问。
class MyClass { public: void normalFunc() { // 普通成员函数 std::cout << "This is a normal function" << std::endl; } }; MyClass obj; obj.normalFunc(); // 通过对象调用
- 静态成员函数:可以通过类名直接调用,也可以通过对象调用,但推荐通过类名调用。
class MyClass { public: static void staticFunc() { // 静态成员函数 std::cout << "This is a static function" << std::endl; } }; MyClass::staticFunc(); // 通过类名调用 MyClass obj; obj.staticFunc(); // 也可以通过对象调用
总结对比
调用方式 |
必须通过对象来调用 |
可以通过类名或对象来调用 |
访问成员变量 |
可以访问所有非静态和静态成员 |
只能访问静态成员,不能访问非静态成员 |
指针 |
有
指针,指向当前对象 |
没有
指针 |
适用场景 |
当需要操作对象的状态或成员时使用 |
当需要与类本身相关,但不需要访问对象时使用 |
3.简述C++从代码到可执行二进制文件的过程
预处理
- 预处理是编译过程的第一步,它的主要任务是处理所有的预处理指令(如
#include
、#define
等),并生成一个纯净的 C++ 源代码文件。生成一个预处理后的.i
文件,其中包含了宏替换、头文件内容和注释已去除的代码。
编译
- 编译阶段的主要任务是将预处理后的源代码转换成汇编语言代码。编译器会对源代码进行语法分析、词法分析、语义分析等,生成对应的汇编语言代码。生成一个汇编语言文件(
.s
文件),其中包含了计算机能理解的低级汇编指令。
汇编
- 汇编阶段将生成的汇编语言代码转化为机器码(对象代码),并生成目标文件(
.o
或.obj
文件)。汇编器将汇编代码转换成机器语言代码,但尚未处理代码中可能存在的外部依赖(如函数调用和全局变量)。生成一个目标文件(.o
或.obj
),它包含机器代码和符号信息,但还未能完全独立执行。
链接
- 链接是将一个或多个目标文件与所需的库文件(如标准库、第三方库等)合并成一个完整的可执行文件的过程。链接分为两个阶段:静态链接和动态链接。生成一个完整的可执行二进制文件(通常是
.exe
文件,在 Unix 系统中是没有扩展名或.out
),此时的程序可以独立运行。
可执行文件
- 最终,经过链接生成的可执行文件是程序可以运行的形式。它包含了所有的代码、数据和必要的符号信息,操作系统可以将其加载到内存中执行。
总结:
预处理 |
处理宏定义、头文件包含、条件编译等 |
预处理后的源代码文件( |
编译 |
将源代码转化为汇编语言 |
汇编语言文件( |
汇编 |
将汇编语言转化为机器码 |
目标文件( |
链接 |
合并多个目标文件和库文件,解析符号 |
可执行文件(如 |
4.全局变量和局部变量的区别?
作用域
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
嵌入式/C++八股 文章被收录于专栏
本人双飞本,校招上岸广和通。此专栏覆盖嵌入式常见面试题,有C/C++相关的知识,数据结构和算法也有嵌入式相关的知识,如操作系统、网络协议、硬件知识。本人也是校招过来的,大家底子甚至项目,可能都不错,但是在面试准备中常见八股可能准备不全。此专栏很适合新手学习基础也适合大佬备战复习,比较全面。最终希望各位友友们早日拿到心仪offer。也希望大家点点赞,收藏,送送小花。这是对我的肯定和鼓励。 持续更新