C++面试基础知识整理(1)

参考链接

GitHub:C++面试基础知识总结

基础知识

源文件从文本到可执行文件经历的过程

  1. 预处理,根据文件中的预处理指令来修改源文件的内容。如#include指令,作用是把头文件的内容添加到.cpp文件中,产生.ii文件,

  2. 编译,将其翻译成等价的中间代码或汇编代码,产生汇编文件(.s文件)

  3. 汇编,把汇编语言翻译成目标机器指令,产生目标文件(.o或.obj文件)

  4. 链接,例如,某个源文件中的函数可能引用了另一个源文件中定义的某个函数;在程序中可能调用了某个库文件中的函数,产生可执行文件(.out或.exe文件)

C++11的新特性

  • 自动类型推导auto、范围for循环、lambda表达式、智能指针、多线程等

C++98&C++11的区别

gcc不同优化等级的区别

  • -O0:不作任何优化
  • -O1:对程序做部分编译优化,对于大函数,优化编译占用稍微多的时间和相当大的内存。使用本项优化,编译器会尝试减小生成代码的尺寸,以及缩短执行时间,但并不执行需要占用大量编译时间的优化。 它主要对代码的分支,常量以及表达式等进行优化。
  • -O2:编译器会试图提高代码性能而不会增大体积和大量占用的编译时间。会尝试更多的寄存器级的优化以及指令级的优化,它会在编译期间占用更多的内存和编译时间。
  • -O3:使用伪寄存器网络,普通函数的内联,以及针对循环的更多优化。
  • -Os:主要是对代码大小的优化

gcc -O0 -O1 -O2 -O3 四级优化选项及每级分别做什么优化

C++的内存管理

  • 该内容存疑

  • 一个程序被加载到内存中,这块内存首先就存在两种属性:静态分配内存和动态分配内存。

    扫描二维码关注公众号,回复: 12686136 查看本文章
    • 静态分配内存:是在程序编译和链接时就确定好的内存。
    • 动态分配内存:是在程序加载、调入、执行的时候分配/回收的内存。
  • 代码段: 代码段(code segment/text segment)通常是指用来存放 程序执行代码 的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于 只读 , 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些 只读的常数变量 ,例如字符串常量等。程序段为程序代码在内存中的映射.一个程序可以在内存中多有个副本.【存储的是二进制后的程序代码】

  • 数据段 :数据段(data segment,也叫GVAR global value)通常是指用来存放程序中 已初始化 的 全局变量 的一块内存区域。数据段属于静态内存分配。 【存储全局已初始化的变量】

  • BSS段:(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。【存储全局未初始化的变量】

  • 堆(heap) :堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc/free等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张)/释放的内存从堆中被剔除(堆被缩减)【存储初始化的局部变量】

  • 栈(stack) :栈又称堆栈, 存放程序的 局部变量 (但不包括static声明的变量, static 意味着 在数据段中 存放变量)。除此以外,在函数被调用时,栈用来传递参数和返回值。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。储动态内存分配,需要程序员手工分配,手工释放**【存储动态未初始化变量】**

  • img

C++——程序的内存结构

问题

堆和栈的区别

  • 堆是由低地址向高地址扩展;栈是由高地址向低地址扩展

  • 堆中的内存需要手动申请和手动释放;栈中内存是由OS自动申请和自动释放,存放着参数、局部变量等内存

  • 堆中频繁调用malloc和free,会产生内存碎片,降低程序效率;而栈由于其先进后出的特性,不会产生内存碎片

  • 堆的分配效率较低,而栈的分配效率较高

A* a = new A; a->i = 10;在内核中的内存分配上发生了什么

  • A *a:a是一个局部变量,类型为指针,故而操作系统在程序栈区开辟4/8字节的空间(0x000m),分配给指针a。

  • new A:通过new动态的在堆区申请类A大小的空间(0x000n)。

  • a = new A:将指针a的内存区域填入栈中类A申请到的地址的地址。即*(0x000m)=0x000n。

  • a->i:先找到指针a的地址0x000m,通过a的值0x000n和i在类a中偏移offset,得到a->i的地址0x000n + offset,进行*(0x000n + offset) = 10的赋值操作,即内存0x000n + offset的值是10。

全局变量、static变量初始时间

  • 对于C语言的全局和静态变量,不管是否被初始化,其内存空间都是全局的;如果初始化,那么初始化发生在任何代码执行之前,属于编译期初始化。
  • C++标准定为全局或静态对象是有首次用到时才会进行构造,并通过atexit()来管理。在程序结束,按照构造顺序反方向进行逐个析构。
  • 全局变量、文件域的静态变量和类的静态成员变量在main执行之前的静态初始化过程中分配内存并初始化;局部静态变量(一般为函数内的静态变量)在第一次使用时分配内存并初始化。这里的变量包含内置数据类型和自定义类型的对象。

文件重定义

// Person.h
class Person
{
    
    
    ...
}

// Worker.h
#include"Person.h"
class Worker : public Person
{
    
    
    ...
}

// Farmer.h
#include"Person.h"
class Farmer : public Person
{
    
    
    ...
}
  • 在Farmer.h和Worker.h中都包含了Person.h,导致Person这个类被重定义了。

  • 使用宏定义解决:

// Person.h
#ifndif PERSON_H
#define PERSON_H
class Person
{
    
    
    ...
}
#endif

条件编译

作用

  • 根据预先定义的参数选择性的编译代码,以使代码适用于不同的运行环境等。比如环境中未安装ROS(机器人操作系统),则可以不对ROS部分的代码进行编译,不至于编译不通过。

使用

  • CMakeLists.txt中
option(USE_ROS "use ros" ON)
IF(USE_ROS)
	message(STATUS "Build with ros")
	add_defination(-D_ROS_)
ENDIF(USE_ROS)

IF(USE_ROS)
	# 通过判断USE_ROS是否启用来选择性编译下面指令
	find_package(catking ...)
ENDIF(USE_ROS)
  • C/C++代码中
#ifdef _ROS_ // 与CMakeLists.txt中USE_ROS或_ROS_名称一致
#include<ros/ros.h>
#endif

猜你喜欢

转载自blog.csdn.net/qq_34731182/article/details/113418270