进程虚拟地址空间区域划分
int data1;
int data2 = 0;
int data3 = 10;
const int data4;
const int data5 = 0;
const int data6 = 10;
int main()
{
int data7;
int data8 = 0;
int data9 = 10;
const int a;
const int b = 0;
const int c = 10;
}
这里有四种变量,分别是全局变量、静态全局变量、局部变量和静态局部变量,每一种变量我有分别定义了未初始化变量,初始化为0变量和初始化不为0的变量,那么在编译运行的过程中这些都分别存放在什么位置呢?
任何编程语言编译时会产生两种东西,即指令和数据 运行时,程序会从磁盘加载到内存中(虚拟内存而非物理内存),这时,系统会给当前进程分配4G的虚拟地址空间(X86体系32位 linux系统)
所有的全局变量和静态局部变量都是数据,编译时会在符号表中产生符号,初始化且不为0的放在.data 段,未初始化或初始化为0的放在.bss段
普通的局部变量,不产生符号,生成指令,存放在.texe段
存放在.bss 段未初始化的数据会被系统自动初始化为0;
每一个进程的用户空间都是私有的,但内核空间是共有的。
什么是虚拟?
它存在,你能看得见,它是物理的
它存在,你看不见,它是透明的
它不存在,你却看的见,它是虚拟的
它不存在,你也看不见,它被删除了
函数调用堆栈的过程
栈是一种特殊的数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。
它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。
栈有很多自己的特性,它具有记忆功能,对栈的插入与删除操作中,不需要改变栈底指针;而且栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。因此栈作用就是用来保持栈帧的活动记录(即函数调用)。
函数运行时要在栈帧上开辟空间,我们用栈顶指针esp和栈底指针ebp来描述一个栈。
函数调用:
先压实参,从右向左压栈
把调用方函数的栈底地址记录在当前函数的栈底内存里(push ebp) 把主调方函数的栈底地址入栈
把ebp指针从调用方函数栈底拉到被调用方函数栈底(mov ebp,esp) 使ebp指向当前函数栈底
C ++的编译链接原理
程序执行包括预编译、编译、汇编和链接几个过程
预编译:处理预处理指令,以#开头的命令,define就是在这时候进行替换的
编译:语法(词法分析),语义分析,代码优化
汇编:生成可重定位的目标文件(.o文件)
.o文件的格式组成
elf文件头 .text .data .bss .symbal section table
编译过程中符号是不分配虚拟地址的(地址为0)
链接:编译完成的所有.o文件和静态库文件
.o文件对应的各段进行和并
符号表合并后,进行符号解析,所有对符号的引用都要找到该符号定义的地方(引用可以后多个,定义只能有一个)
符号的重定位:给所有的符号分配虚拟地址
把原来的0地址填充成正确地址
形参带默认值的函数
int sum(int a, int b)
{
return a + b;
}
int main( )
{
int a = 10;
int b = 20;
int c = sum(a, b);
return 0;
}
一般的函数调用
int sum(int a=20, int b=30)
{
return a + b;
}
int main( )
{
int a = 10;
int b = 20;
int c = sum(a, b);
return 0;
}
形参带默认值的函数
如果传入了实参,调用是就会代入实参的值,如果函数调用时没有传入实参,则使用默认值
形参的默认值必须从右向左给,如以下是错的
int sum(int a=20, int b)
{
return a + b;
}
int main( )
{
int a = 10;
int b = 20;
int c = sum(a, b);
return 0;
}
调用效率上,直接传入立即数要比变量快一些,底层上少一次mov指令,不用再去内存里取值
也可以在函数声明时给形参默认值,但默认值只能出现一次,就算值一样
inline内联函数
内联函数和普通函数的区别?
在编译过程中,就没有函数的调用开销了,在函数的调用点 直接把函数代码进行展开处理了
inline函数不再生成相应的函数符号
但不是所有的inline都会被编译器处理成内联函数(递归)
inline知识建议编译器把这个函数处理成内联函数,且内联函数只有在release版本下才能出现
函数重载
什么是函数重载?
一组函数,函数名相同,参数列表的个数或类型不同,这组函数就叫做重载函数
重载的函数要处在同一个作用域
为什么c++支持函数重载而c语言不支持?
因为二者生成符号的规则不同,c++代码产生函数符号时,函数名加参数列表的类型组成
c代码产生符号时,生成的是函数名,这样如果一组函数函数名相同,不就找不到他的定义了么
不同的作用域可以定义相同名称的变量,调用时就近调用,即如果声明了函数,那么调用时调用声明就够了
一组函数函数名相同,参数列表页相同,仅仅是返回值不同,不叫函数重载
用c调用c++时,把c函数的定义括在extern"c"里
c++调用c时,把c函数的声明括在extern"c"里