1. 进程虚拟地址空间划分
从操作系统角度下:
mov dword ptr[a],0Ch
首先这是一个指令,表示在栈上划分一个4字节的内存空间,把0Ch这个数据放到dword ptr[a] (a这块内存的4字节内存里边)
静态局部变量:第一次运行到他们的时候进行初始化
在内核空间划分了一份可以共享的内存。
注意:虚拟地址空间与虚拟内存不是一个概念!!!
2. 函数调用堆栈过程
在C语言里面
<=4 eax
4&&<=8 eax edx
8产生临时量带出返回值了!!!
3. C++编译链接原理
对于其他文件定义的变量或函数,我在另外一个文件里引用会产生指令但是无法知道它存放在哪个位置!!!
会产生符号
.o文件的格式组成参考《深入理解计算机系统》
elf header:
program header:
符号的重定向:将新的地址写入引用处相关变量的指令里头。
数据放的是相应符号的虚拟地址,函数放的是偏移量。
4. 形参默认值
#include <iostream>
using namespace std;
int sum(int a, int b = 20);
int sum(int a = 10, int b);
int main()
{
int a = 10;
int b = 20;
int ret = sum(a, b);
return 0;
}
int sum(int a, int b)
{
return a + b;
}
1.给默认值的时候只能从右向左给。
2.调用效率问题,变量传参,会先把变量赋值给寄存器。如果是立即数sum(10,20) 和默认参数它就会直接存在于寄存器中,相对于变量就会少一行汇编指令。相当于直接给默认值。
3.定义处可以给形参默认值,声明也可以给形参默认值。
4.形参给默认值的时候,不管是定义处给,还是声明处给,形参默认值只能出现一次。
5. inline
#include <iostream>
using namespace std;
inline int sum(int x, int y)
{
int a = 10;
int b = 20;
return x + y;
}
int main()
{
int a = 10;
int b = 20;
int ret = sum(a, b);
return 0;
}
内联函数与普通函数的区别???
- inline内联函数在编译过程中,没有函数调用开销,在函数的调用点直接把函数的代码进行展开处理,不再生成相应的函数符号
- inline只是建议编译器将其处理成内联函数,不是所有的inline都会被编译器处理成内联函数 - 递归(递归也有可能出现内联函数)、代码太复杂
- debug版本上,inline是不起作用的;inline只有在release版本下才能出现。
可以打开虚拟机:g++ -c main.cpp -O2 objdump -t main.o去看一下就不会生成调用函数的指令了!!!
6. 重载、隐藏、覆盖
#include <iostream>
using namespace std;
/*
函数重载
1. C++为什么支持函数重载,C语言不支持函数重载?
C++代码产生函数符号的时候,函数名+参数列表类型组成的!
C代码产生函数符号的时候,函数名来决定!
2. 函数重载需要注意些什么?
3. C++和C语言代码之间如何调用?
什么是函数重载?
1. 一组函数,其中函数名相同,参数列表的个数或者类型不同,那么这一组函数称为函数重载。
2. 一组函数要称得上重载,一定是要处在同一个作用域当中的。
3. const或者volatile的时候,是怎么影响形参类型的?
4. 一组函数,函数名相同,参数列表也相同,仅仅是返回值不同,不叫重载。
请你解释一下,什么是多态?
静态(编译时期)的多态:函数重载、模板
动态(运行时期)的多态:重写
什么是函数重载?
同一个作用域下:函数名相同,参数列表不同,这样的一组函数我们称他们为函数重载。
C -> C++ 把C++函数的定义括在extern "C"里面。
C++ -> C 把C函数的声明括在extern "C"里面。
*/
bool compare(int a, int b) // compare_int_int
{
cout << "compare_int_int" << endl;
return a > b;
}
bool compare(double a, double b) // compare_double_double
{
cout << "compare_double_double" << endl;
return a > b;
}
bool compare(const char* a, const char* b) // compare_const char*_const char*
{
cout << "compare_char*_char*" << endl;
return a > b;
}
int main()
{
bool compare(int a, int b); // 函数的声明
compare(10, 20);
compare(10.0, 20.0); // double -> int
compare("aaa", "bbb"); // const char* -> int
return 0;
}
- C++为什么支持函数重载?C语言为什么不支持函数重载?
C++代码产生函数符号的时候,函数名+参数列表类型组成的!
C代码产生函数符号的时候,函数名来决定!
(2)函数重载需要注意一些什么?
- 一组函数,其中函数名相同,参数列表的个数或者类型不同,那么这一组函数称为函数重载。
- 一组函数要称得上重载,一定是要处在同一个作用域当中的。
- const或者volatile的时候,是怎么影响形参类型的?
- 一组函数,函数名相同,参数列表也相同,仅仅是返回值不同,不叫重载。
面试官让你解释函数重载:
同一个作用域下,函数名相同,参数列表不同的这样一组函数称为一组重载函数。
(3)多态(以后细讲)
静态多态(编译期)(为什么是编译期:因为压栈,初始化栈指令等需要在编译期就确定好。):重载、模板
动态多态(运行期):重写
(4) C++和C语言代码之间如何调用?
C -> C++ 把C++函数的定义括在extern "C"里面。
C++ -> C 把C函数的声明括在extern "C"里面。
(5)介绍一下宏定义
如果在C++编译期中,就extern “C”,否则就不extern "C",这样对于代码编译成函数符号的时候就更加灵活。
7. const
(1)C/C++const的不同
#include <iostream>
using namespace std;
/*
const 指针 引用 在函数当中的应用
const怎么理解?
const修饰的变量不能够在作为左值!!! 初始化完成后,值不能被修改!!!
C和C++中const的区别是什么?
C:const修饰的量,可以不用初始化,不叫常量叫常变量。
C++:const修饰的量,必须初始化,叫常量。
它们俩的编译方式不同,C中,const就是当作一个变量来编译生成指令的。C++中,所有出现const常量名字的地方,都被常量的初始值替换了!!!
当初始值变为一个变量,就退化成常变量了。
*/
int main()
{
int b = 20;
const int a = /*20*/b;
int* p = (int*)&a;
*p = 30;
cout << a << *p << *(&a) << endl;
return 0;
}
(2)const与一级指针/二级指针的结合
/*
const和一级指针的结合
const和二级(多级)指针的结合
const修饰的量 叫常量
和普通变量的区别是什么? C++有两点区别? 1. 编译方式不同 2. 不能作为左值了
const修饰的量常出现的错误是:
- 常量不能再作为左值 《= 直接修改常量的值
- 不能把常量的地址泄漏给一个普通的指针或者普通的引用变量 《= 可以间接修改常量的值
const和一级指针的结合:有两种情况
C++的语言规范:const修饰的是离它最近的类型
const int *p;
可以任意指向不同的int类型的内存,但是不能通过指针间接修改指向的内存的值
int const* p;
int* const p;
这个指针p现在是常量,不能再指向其他内存,但是可以通过指针解引用修改指向的内存的值
const int* const p;
总结const和指针的类型转换公式:
int* <= const int* 是错误的
const int* <= int* 是可以的
int** <= const int** 是错误的
const int** <= int** 是错误的
int** <=int const 是错误的
intconst <= int** 是正确的
const右边如果没有指针*的话,const是不参与类型的
*/
8. 左值与右值引用
/*
右值引用
1. int&&c = 20; 专门用来引用右值类型,指令上可以自动产生临时量,然后直接引用临时量 c = 40;
2. 右值引用变量本身是一个左值,只能用左值引用来引用它;
3. 不能用一个右值引用变量来引用一个左值。
*/
int main()
{
int a = 10; // 左值,它有内存,有名字,值可以修改
int& b = a;
//int& c = 20; // 20是右值:没内存,没名字
// C++11提供了右值引用的核心
int&& c = 20; // 底层上先生成一个临时量,然后将临时量的地址放到了寄存器的地址里,最后将寄存器的值给了c。
int& e = c; // 一个右值引用变量,本身是一个左值
const int& d = 20; //底层指令跟右值引用一模一样的,不一样的地方在于d不能再作为左值了。
return 0;
}