IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> [C++初阶笔记]P2 -> 正文阅读

[C++知识库][C++初阶笔记]P2

常引用(const修饰的引用/权限放大和缩小)

1、权限放大和缩小只针对引用和指针

int main()
{
 ? ?//权限的平移
 ? ?int a = 10;
 ? ?int& b = a;
?
 ? ?//只读 > 可读可写 属于权限放大的情况(不能放大)
 ? ?const int a1 = 10;
 ? ?int& b1 = a1;//编译错误,a1为常量。
?
 ? ?//可读可写 > 只读 属于权限的缩小的情况(可以缩小)
 ? ?int a2 = 10;
 ? ?const int& b2 = a2;
?
 ? ?//隐式类型转换(整型提升/算术提升)
 ? ?//这里类型转换的过程中会产生一个double的临时变量,它是算术提升a3的结果,最终是将临时变量赋值给b3.
 ? ?//类型转化并不会对变量a3产生影响,而是得到变量a3的值,对值进行操作。
 ? ?//这里引出隐式类型转换是为了更好得理解下面提到的临时变量
 ? ?int a3 = 10;
 ? ?double b3 = a3;
?
 ? ?//b4引用的不是a4,引用的是中间产生的临时变量,临时变量本身具有常性,相当于被const修饰的一样。
 ? ?//这里不能被引用的真正原因是因为权限的放大,权限不能放大的。
 ? ?int a4 = 10;
 ? ?double& b4 = a4;//编译错误,临时变量具有常性。
?
 ? ?//权限的平移
 ? ?int a5 = 10;
 ? ?const double& b5 = a5;
?
 ? ?//虽然精度丢失,但并不会权限放大,所以可行。
 ? ?double a6 = 3.14;
 ? ?const int& b6 = a6;
?
 ? ?//给字面常量取别名
 ? ?const int& a7 = 10;
 ? ?
 ? ?int& a8=10;//编译错误,10为字面常量。
 ? ?return 0;
}

类型转换/引用过程 中间会产生临时变量,临时变量本身具有常性。

2、引用作为函数形参时可能导致的权限放大

权限放大和缩小只针对引用和指针

void func1(int n)
{}
void func2(int& n)
{}
void func3(const int& n)//如果使用引用传参,并且函数内并不改变引用,则需要用const修饰。和指针一样。
{}
int main()
{
 ? ?int a=10;
 ? ?const int b=20;
 ? ?
 ? ?func1(a);
 ? ?func1(66);
 ? ?func1(b);//虽然传递的b是有const修饰,func1的形参类型没有const修饰,但传递参数仅仅是拷贝。
             //func1函数中n的改变不会影响b。
 ? ?
 ? ?func2(a);
 ? ?func2(b);//编译错误,因为b是被const修饰的,形参没有const修饰,n的改变会影响b,相当于权限放大。
 ? ?func2(66);//编译错误,同理。
 ? ?
 ? ?func3(a);
 ? ?func3(b);
 ? ?func3(66);
 ? ?return 0;
}

引用和指针的区别

1、引用定义时必须初始化,指针定义时不一定要初始化。

2、引用初始化后不能再引用其他实体,指针可以修改指向任意对应类型的变量。

所以引用不能引用于链表

3、没有空引用,但有空指针。

4、没有多级引用,有多级指针。

5、语法角度来说创建引用不开空间。底层角度,sizeof(引用)为引用类型的大小,sizeof(指针)为4/8字节

底层是按照指针的方式实现的,如下汇编代码对比是一样的。

?

?

6、引用++结果是引用的实体增加1,指针++即指针向后偏移一个类型的大小。

7、访问实体方式不同,指针需要通过*解引用,引用则编译器会自己处理。

8、 指针比引用危险,指针比引用强大。

C++是如何支持函数重载的

1、C/C++代码运行起来需要经过:预编译、编译、汇编、链接。

?

?

预编译:头文件的展开、宏的替换、条件编译、消除注释。

  1. func.h分别在func.c和main.c中展开。

  2. 最后生成func.i和main.i文件

编译:语法检查,生成汇编代码。

func.i和main.i编译后生成汇编代码func.s和main.s(CPU读不懂汇编代码)

汇编:汇编代码转化成二进制机器码。

生成二进制的目标文件func.o和main.o(windows环境下为.obj)

链接:不仅仅是把.o目标文件合并,还要找到声明过的函数/变量的地址

  1. func.o中的函数定义可直接转化为二进制指令

  2. main.o中只包含函数声明,并不知道函数定义的具体过程,链接过程需要中把func.o中函数(定义)的地址传给main.o的函数调用。

  3. 如果链接过程中,main.o中的函数调用时找不到对应的函数(定义)的地址,就会报链接错误。

  4. 每个.o目标文件都会配一个符号表,符号表是函数名/变量名和它们自身地址的映射。

  5. 链接过程中就会拿函数名去符号表中找对应的地址,而C语言的目标文件中的符号表无法区分同名函数。

  6. 生成out.a可执行文件(Windows环境下为.exe)

2、链接的一些细节

?

?

  • .o文件是汇编代码转成的机器码

  • func.o文件中有函数的定义,对应的汇编代码就会建立栈帧的过程。

  • main.o文件中只有函数调用,没有建立栈帧的过程,但是前面函数声明,编译就会允许通过。

  • func.o有函数的定义才会有函数的地址,main.c只有函数声明没有函数地址。

  • 有定义才会有符号表,声明不会进符号表。

  • 链接就是通过符号表拿着函数名把声明过的函数地址找到,找不到就会报链接错误。

  • 全局变量和函数都会记录到符号表

  • 查看符号表:objdump -S [可执行文件名]

3、函数名修饰规则

?

C++为了支持函数重载,编译时会有一个函数名修饰规则,

Linux下符号表中函数名的修饰规则

1、_Z是前缀

2、4表示函数名的长度

3、func表示原本的函数名

4、id表示所有参数类型首字母组合

所以参数个数/类型种类/类型顺序不同,都会引起修饰后的函数名不同。从而也能看出函数重载与函数返回类型无关。

C++程序调用C库

1、用VS生成一个C的静态库。

  • VS默认生成可执行程序(没有main函数就会报错)

  • 将函数声明文件和函数定义文件写好

  • 解决方案资源管理器>右击项目名>属性>常规>配置类型>静态库.lib>应用>生成解决方案

  • 在输出中会显示生成的静态库路径

2、写一个C++调用C静态库的代码

  • 先要包含头文件:#include"生成静态库的头文件的相对路径(或绝对路径)"

  • 也可以直接拷贝到当前路径,只写头文件名字。

  • 代码编译完后链接的时候才会去链接静态库

3、配置链接器设置

  • 解决方案资源管理器>右击项目名>属性>链接器>常规>附加库目录>添加静态库的目录>应用

  • 解决方案资源管理器>右击项目名>属性>链接器>输入>附加依赖项>编辑>添加库的名称>应用

4、extern "C" 告诉C++编译器,链接的时候按C的函数名修饰规则去库中寻找函数

extern "C"
{
    #include"../StackC/Stack.h"
}

C程序调用C++库

1、用VS生成一个C++的静态库。

  • 解决方案资源管理器>右击项目名>属性>常规>配置类型>静态库.lib>应用>生成解决方案

2、写一个C调用C++静态库的代码

  • 先要包含头文件:#include"生成静态库的头文件的相对路径(或绝对路径)"

  • 也可以直接拷贝到当前路径,只写头文件名字。

3、配置链接器设置

  • 解决方案资源管理器>右击项目名>属性>链接器>常规>附加库目录>添加静态库的目录>应用

  • 解决方案资源管理器>右击项目名>属性>链接器>输入>附加依赖项>编辑>添加库的名称>应用

4、按C的函数修饰规则去生成C++库的符号表。

C程序调用C++库需要包含C++库方法的头文件

//C代码包含的头文件
#include"C++静态库头.h文件的路径"

C++库方法的头文件中的函数声明要被extern "C"修饰的,以C的函数修饰规则生成符号表。

//生成C++静态库的.h文件中的代码
extern "C"
{
 ? ?//函数声明
}

C程序包含了C++库方法的头文件,那么就会在C程序中展开。

//预处理后的C代码
extern "C"
{
 ? ?//函数声明
}

展开后但是C的编译器不认识 extern "C"就会报错,所以要使用条件编译,让其在生成C++静态库时按extern "C"来执行,在C代码中展开后不执行。

//C++库方法的头文件
#ifdef __cplusplus
extern "C"
{
#endif
    //函数声明
 ? ?//函数声明
    //函数声明
#ifdef __cplusplus
}
#endif

C++程序就会定义__cplusplus,C程序不会。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-31 11:35:33  更:2022-10-31 11:37:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 3:30:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码