C++初探:c和c++的区别简述,以及编译器对代码做了什么?

准备将自己之前学过的C++再重新温习,顺便和大家交流,因为我知道分享是学习过程中对自己或他人很重要的一点,所以我来了!
该博文为本作者原创,转载请注明出处!
1、C和C++的区别(之前C语言基础较为扎实的,可直接从这些方面学习C++)
1)运算符的重载
2)模板(函数和类)
3)继承和多态
4)C++的I/O流
5)C++的异常
6)STL,Boost
2、指令和数据
1)指令:不产生符号,不运行时在代码段,编译时产生汇编语言。
整个函数块产生一个符号,那就是函数名。
2)数据:产生符号,一般全局变量和局部静态变量为数据。
int x=0; //数据
int y; //数据
int main()
{
int z=0; //指令
int d=0; //指令
static int m=11; //数据
return0;
}
指令是一个函数块,会产生一个符号,那就是函数名。
3.虚拟地址空间
一般我们所用的电脑都是inter X86 32位体系的处理器
这里所说的32是指电脑的位数,也就是CPU位数,也就是CPU处理数据的运算能力,也就是ALU(算术逻辑单元)的宽度,也是总线(数据总线)位数,也就是说cpu一次运算四个字节。
从32位也可以得到系统中每一个进程在运行时,都会各自产生2的32次方也就是4G的虚拟内存空间,虚拟就是不存在的你也看不到的,也就是逻辑上抽象出来的一个内存,每个进程在运行的时候都会一位自己有4G的运行空间。
一般如果我们的电脑是64位的话,尽量装一个64位的操作系统,避免资源浪费。
接下来认识一下我们的地址空间:
这里写图片描述
1)除了空洞区域,程序在执行的时候就给他空间进行了相应分配,直到代码中出现malloc等才会开辟堆空间。
2)共享库是引用头文件,运行程序时,加载动态库在空洞区域。
动态库 静态库
Windows .dll .ao
Linux .so .lib
静态库和动态库的区别在于,动态库是在编译链接时标记,在运行时将实现方法加载。而静态库是在编译链接时就将实现方法加载到程序中,运行时不需要加载。所以静态库的执行效率高,但动态库的程序体积小。
3)由于权限的问题,用户空间不能访问内核空间。同时也由于内核空间和用户空间映射地址机制不同,内核态也不能在用户态进行操作。
4)对于所有的进程,内核空间是共享的,而用户空间则是相互独立的。比如:当我们有多个进程同时打开同一文件进行读写操作时,(打开文件时从磁盘加载到文件缓冲区再到内存)当我们调用的是系统的库函数(用户空间)时,每个进程之间相互独立,各自往文件中写数据,而当我们调用open(是否带缓冲区视情况而定) write read close 等系统调用时,就进行了和内核空间的交互,多个进程将相互知道对文件的操作情况。(用户只有调用系统API才能和内核进行交互。)
5) .bss : 存放的是没有被初始化,或者初始化为0的数据
.data : 存放的是初始化的但初始化不为0的数据(全局变量和静态局部变量)
操作系统会将.bss中的值统一初始化为0,.bss不占文件大小,逻辑上存在,占虚拟内存并记录信息
6)在VC的.C中打印未初始化的局部变量的时候,会出现无效值(烫,屯,0xcccccccc)
4. 编译:
1)预编译(宏替换,预处理指令以“#”开头的处理)———–编译(语法检查,优化代码,汇总符号)————汇编(生成.obj,产生符号表)
当有多个源文件时,他们是各个独自编译。
2)在说到优化代码,那就不得不提到volatile关键字。Volatile主要是禁止进行代码的优化。
比如:
volatile int a=10;
int main()
{
int m;
int n;
m=a;
n=a;
}
由于代码的优化,在多线程的环境下,第一次从内存-控制总线-地址总线-数据总线-将值a=10赋值给m;第二次将直接从寄存器中拿数据赋值给n,而并不从内存中拿取。如果加上volatile关键字,则将禁止a的优化,每次调用a时就会从内存中拿而不是寄存器。

读者可以思考下:
**上述代码不加vlatile关键字如果在多线程环境下会出现什么问题?
不直接从内存中拿数据,会出现什么影响?**

3)CPU在进行数据处理时,读取速度依次排序为:
寄存器—CPU中的高速缓冲区—内存—磁盘(快—>慢)
4)普通的未被初始化的全局变量,在编译链接时,在COM段中(弱符号),在生成可执行文件之后在.bss段中(强符号)。
5)C语言中,链接的时候,当多个目标文件出现相同名字的全局变量时会出现重定义,编译器默认初始化的全局变量为强符号,未被初始化的全局变量是弱符号。不能同时出现两个强符号,否则将编译不通过,如果是两个弱符号,则将选择字节较长的那个弱符号。如果一个强符号,一个弱符号,则选择强符号。
比如:
在1.cpp中:
int x;
void fun()
{
x=20;
}
在2.cpp中:
void fun();
Short x=10;
Short y=10;
int main()
{
Printf(“%d %d”,x,y);
}
以上的两个源文件是各自编译的,在1.cpp中由于int x是弱符号,但是它在编译完成后已经生成汇编语言(要将20赋值给四个字节)。而在2.cpp中由于short是强符号,所以最终结果short将为x的类型。但是1.cpp中已经默认要将20赋值给四字节。所以 0x10 00 00 00将覆盖x y的内存空间,最终将0x10放入x,将0x00放入y,打印结果为20,0
5.链接阶段:
这里写图片描述
1)main.0的组成:
在Linux下main.o是elf文件格式,在windows下是PE文件格式
这里写图片描述
Symbol table:
这里写图片描述
编译阶段的时候会优化代码,汇总符号(编译->汇编->二进制)
反汇编: 二进制 –> 汇编
声明也会产生符号 C++中无强弱符号
编译阶段: 在当前文件中引入了外部符号,数据,指令,会产生未定义符号UND ;未分配合理虚拟地址。
2)编译阶段的残留(.obj为什么无法运行):
a)编译阶段使用外部数据地址 0x00 00 00 00
编译阶段使用外部函数调用地址 FC FF FF FF(-4)
b)符号未分配地址
而这些编译阶段的残留,都将在链接阶段解决
3)链接的步骤:
a)合并.obj文件中的各个段(.data和.data合并,.text和.text合并),调整每一个段的起始位置和段本身的大小(段表),进行符号解析(从引用到定义的地方)
b)给符号分配虚拟地址 -> 符号重定位
符号重定位就是将编译阶段未决的数据地址直接替换为绝对虚拟地址,将未决的指令地址替换为偏移量 (偏移量+下一条指令地址=绝对虚拟地址)
Cpu在执行指令的时候是从PC寄存器中读取指令,而PC寄存器中存放的是正在执行的这条指令的下一条地址。

4)可执行文件:.exe是由.obj文件和库文件链接之后生成
这里写图片描述
可知,.exe文件相对于.obj文件多了一个program header,与此同时,elf header中也应多出一个start of program header。
Load项中记录从哪加载以及加载的大小
在通过Loader加载器往内存中加载时,只加载数据和指令。
相同属性的段会被放在同一个页面,这是由Load想来决定的
由于load加载时是根据页面对齐的,很大程度会造成内存碎片
(如何节省内存碎片在《程序员的自我修养的第六章提及》)
磁盘->程序运行->产生虚拟4G内存->映射到物理内存

6.交换分区,虚拟内存,虚拟地址空间的区别
交换分区:系统分盘时牺牲掉的一块区域,用来存放非活动页面
虚拟内存:一种内存管理机制。抽象技术,内存和I/O的资源管理
虚拟地址空间:逻辑上的抽象,每一个数字代表一个地址。
虚拟内存机制:
1)使物理内存充当swap分区的高速缓冲区,把活动的页面放到物理内存中,非活动的放到Swap分区中。
2)给每一个进程分配了一个4G大小的虚拟地址空间
3)保证了每一个进程的虚拟地址空间是隔离的。

推荐书籍:《程序员的自我修养》

敝人才疏学浅,博客中若出现错误的知识点,欢迎大家指正。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值