【C++初阶】第一站:C++入门基础(下)

2024-02-26 1828阅读

温馨提示:这篇文章已超过430天没有更新,请注意相关的内容是否还可用!

前言: 

紧接着上两篇文章,c++入门基础(上):C++入门基础(上)

                                 c++入门基础(中):C++入门基础(中)

        继续补充完c++初阶入门基础的知识点,本章知识点包括:

        引用和指针的区别、内联函数、auto关键字(C++11)、基于范围的for循环(C++11)、指针空值nullptr(C++11)等补充知识。

【C++初阶】第一站:C++入门基础(下)

目录

6.引用

6.6 引用和指针的区别

7.内联函数

7.1概念

7.2 特性

8.auto关键字(C++11)

8.1 类型别名思考

8.2auto简介

特别注意:auto不能推导的场景

记住关键字:typeid

9.基于范围的for循环(C++11)

9.1 范围for的语法

10. 指针空值nullptr(C++11)


6.引用

6.6 引用和指针的区别

来看下面代码,右击鼠标转到反汇编:

【C++初阶】第一站:C++入门基础(下)

 可以看到汇编代码,大家都是一样的,解析下面的汇编代码:

dword         双字 就是四个字节 

ptr               pointer缩写 即指针

[]里的数据是一个地址值,这个地址指向一个双字型数据

比如mov eax, dword ptr [a]         把内存地址a中的双字型(32位)数据赋给eax

【C++初阶】第一站:C++入门基础(下)

        lea表示"load effective address",表示对某个变量的地址进行加载,相当于取地址的操作。所以lea eax, [a]就是将a的地址赋给eax寄存器。

接着分别进行以下操作:

【C++初阶】第一站:C++入门基础(下)

一样的转到反汇编:

【C++初阶】第一站:C++入门基础(下)

引用和指针的不同点:(建议别背,从使用的角度区分)

1. 引用概念上定义一个变量的别名,指针存储一个变量地址。

2. 引用在定义时必须初始化,指针没有要求

3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何 一个同类型实体

4. 没有NULL引用,但有NULL指针

5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32 位平台下占4个字节)

6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小

7. 有多级指针,但是没有多级引用

8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理

9. 引用比指针使用起来相对更安全

7.内联函数

复习一下:实现一个ADD的宏函数

#define N 10

以下均为错误案例:

#define ADD(int x,int y) {return x+y;}
#define ADD( x, y) {return x+y;}
#define ADD( x, y) return x+y;
#define ADD(x,y) x+y;
#define ADD(x,y) x+y;
#define ADD(x,y) (x+y);//特别注意一下这一条为什么错误。

解析上面需要注意那条 : 

【C++初阶】第一站:C++入门基础(下)

从以上可以简单看出宏函数的优缺点:

缺点:

1、容易出错,语法坑很多

2、不能调试

3、没有类型安全的检查

优点:

1、没有的类型的严格限制

2、针对频繁调用小函数,不需要再建立栈帧,提高了效率

引出我们的内联函数,也是不需要建立栈帧.

7.1概念

        以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。

【C++初阶】第一站:C++入门基础(下)

        如果在上述函数前增加inline关键字将其改成内联函数, 在编译期间编译器会用函数体替换函数的调用。 查看方式: 1. 在release模式下,查看编译器生成的汇编代码中是否存在 call Add 2. 在debug模式下,需要对编译器进行设置,否则不会展开 ( 因为debug模式下,编译器默认不会对代码进行优化,以下给出vs2019的设置方式 )

在debug设置下默认是不会展开的:

【C++初阶】第一站:C++入门基础(下)

在使用内联函数之前,需要进行以下设置:

【C++初阶】第一站:C++入门基础(下)

展开是什么意思呢,就是不用调用函数,直接把函数里的功能直接拷贝放到main函数内实现:

        而且解决了符号优先级的问题,因为函数传参,是把表达式算出结果再传进去的。

【C++初阶】第一站:C++入门基础(下)

7.2 特性

        inline是一种 以空间换时间的做法,如果编译器将函数当成内联函数处理,在 编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率                inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建 议:将 函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、 不 是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。下图为 《C++prime》第五版关于inline的建议: 【C++初阶】第一站:C++入门基础(下)

【C++初阶】第一站:C++入门基础(下)

编译器视为内联函数

【C++初阶】第一站:C++入门基础(下)

因代码膨胀,编译器不视为内联函数

【C++初阶】第一站:C++入门基础(下)

 add是内联函数,func被编译器视为不是内联函数。

【C++初阶】第一站:C++入门基础(下)

把func函数类冗余的代码删除:

【C++初阶】第一站:C++入门基础(下)

这样就被视作为内联了。

测试代码:

#include
#include
#include
#define ADD(x,y) ((x)+(y))
inline int add(int x, int y)
{
	return x + y;
}
inline int func()
{
	int x1 = 0;
	int x2 = 0;
	int x3 = 0;
	int x4 = 0;
	int ret = 0;
	ret += x1;
    //以下代码全注释掉
	/*ret -= x2;
	ret -= x3;
	ret -= x3;
	ret -= x3;
	ret -= x3;
	ret -= x3;
	ret -= x3;
	ret -= x3;
	ret -= x3;
	ret -= x3;
	ret -= x3;
	ret -= x3;
	ret -= x3;
	ret -= x3;*/
	return 0;
}
int main()
{
	ADD(1, 2);
	printf("%d\n",ADD(1,2));
	printf("%d\n",ADD(1,2)*3);
	int a = 1, b = 2;
	//ADD(a | b, a & b);//(a | b + a&b)
	//int ret = add(1, 2);
	int ret = add(a | b, a & b);
	printf("%d\n",ret);
	ret = func();
	
	}

声明和定义分离

3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址 了,链接就会找不到

测试代码:

Func.h

#pragma once
#include
using namespace std;
inline void  f(int i);
void fx();

Func.cpp

#include"Func.h"
void f(int i)
{
	cout 
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]