1、虚拟内存与物理内存的关系;
虚拟内存是一种实现在计算机软硬件之间的内存管理技术,它将程序使用到的内存地址(虚拟地址)映射到计算机内存中的物理地址,虚拟内存使得应用程序从繁琐的管理内存空间任务中解放出来,提高了内存隔离带来的安全性,虚拟内存地址通常是连续的地址空间,由操作系统的内存管理模块控制,在触发缺页中断时利用分页技术将实际的物理内存分配给虚拟内存,而且64位机器虚拟内存的空间大小远超出实际物理内存的大小,使得进程可以使用比物理内存大小更多的内存空间。
2、代码是被加载到虚拟内存里运行,谁加载?谁运行?该虚拟内存分为几个部分(内核区、不可访问区域);
1. 代码段
存储程序的机器指令,这段区域的内存一般可读可执行,但不可写
2. 数据段
① 存储程序中已经初始化且不为0的全局变量和静态变量
② 这些变量的初值会存储在程序编译后的二进制文件中,然后被加载到内存中
3. BSS(Block Started by Symbol)段
① 存储程序中未初始化或初始化为0的全局变量和静态变量
② 由于他们的初值为0,因此不需要在程序编译后的二进制文件中存储那么多0,只需要记录他们的起止地址即可
③ 操作系统在加载程序时,会根据记录的BSS段起止地址初始化相应的内存区域
④ BSS除了Block Started by Symbol,从功能上也可以理解为Better Save Space
4. 堆 & 栈
堆空间和栈空间不是从磁盘上加载,而是在程序运行过程中申请的内存空间
说明1:Linux 0.11内核支持的a.out文件格式与内存布局,就是如上图所示
说明2:现代应用程序除了上面的内存段,还会包含如下内存区域
① 存放加载的共享库的内存空间
如果一个进程使用共享库(动态库),该共享库的代码段、数据段和BSS段也需要被加载到进程的地址空间中
② 共享内存段
可以通过系统调用映射一块匿名内存作为共享内存,用来进行进程间通信
③ 内存映射文件
可以将磁盘上的文件映射到内存中,用来进行文件编辑或以类似共享内存的方式进行进程间通信
3、全局变量定义后不赋值会直接被初始化为0,为什么?空间是在哪部分配的?
int a; 会被直接初始化为0,是因为直接在.bss段分配的空间,该空间已被系统初始化为0。
int b = 10; 变量的空间是在.data段中分配;
4、static 关键字修饰的(全局或局部)变量的空间是在哪部分配的? (static 关键字 作用: 隐藏、续命)
全局变量默认带有static修饰(对吗?),就是是否赋值,分配到具体的空间里(.bss , .data)
局部变量在定义时设置为static修饰,空间在数据段中,该变量只会被定义初始化一次,且空间会在代码结束后才被系统回收。
5、宏与typedef、内联函数的各自区别
宏可以用文本代替其他任意标识符 , typedef只能对有效的数据类型取别名; 内联函数是用关键字inline函数,本身是函数,编译器会检查该函数的语法是否正确;
#define P 1 (对的)
#define while 1 (错的)
6、volatile关键字的作用
volatile关键字用于告诉编译器不作变量的优化:实质是指定cpu每次读取的值是从内存中读取实际的值,而不是读取cpu寄存器中的值。
7、unsigned int a = -1; int b = 1; if(a>b)(printf("%d",a)):(printf("%d",b));输出结果?
当执行运算时,如果其中一个运算数是有符号的,另一个是没有符号的,C语言会隐式的将有符号的运算数强制转为无符号,并且假设两个数都是非负的来执行运算。在32位和64位的计算机里面-1就是二进制的1111 1111 1111 1111 1111 1111 1111 1111转为十进制就是 4 294 967 295 就是32位无符号的最大值,所以输出结果就是-1;
8、for(;;); 与 while(1);的不同;
for()的执行效率要高于while(),通过汇编代码可以查看到,for()对于一条汇编指令,但是while()对于4条汇编指令;