当前位置:网站首页>return、const、volatile关键字
return、const、volatile关键字
2022-06-23 22:18:00 【云朵c】
文章目录
return关键字
大家想过一个问题吗?当我们在下载一段视频时,假设为3个G,我们需要很长时间,而当我们删除这段视频时,几乎可以说瞬间就删除掉了。这合理吗?
大家知道,任何数据在内存中都以二进制的01存储。那么在下载视频时,就是下载了3个G的0和1,那么删除视频时按正常思维来说就应该是把这3个G的0和1给删除掉,但如果是这样,那么花费的时间应该和下载的时间是相同的。
但既然我们从现象中发现,删除的时间相比下载的时间是非常短的,那么就说明,删除的时候并不是把3个G的0和1给删除掉。而是对这3个G的内存做一些手脚,让这3个G变为失效即可。其实,在计算机中,删除数据并不是真的删除,而是使该数据由不可被覆盖变为可以覆盖。
如何正确理解这段代码?
#pragma warning(disable:4996)
#include <stdio.h>
#include <Windows.h>
char* func() {
char str[] = "hello world!";
return str;
}
int main()
{
char* p = func();
printf("%s\n", p);
system("pause");
return 0;
}
C语言是一门面向过程语言,几乎90%以上的代码都是在代码块内,而在代码块内创建的变量,在出代码块时就会销毁。那么其实这些变量,都是创建在栈上的,每一个函数称为一个栈帧。
我们先来分析上面的代码,func函数会创建一个字符串然后返回该字符串的指针,那么该函数当返回之后,该函数就被销毁了,也就是函数内任何的代码都会消失,那么创建的字符串也会消失,那么返回的指针就变为野指针了。然而事实真是如此吗?

调试过程中,func函数返回指针之后应该是会销毁的,而上面看监视发现,并没有销毁,指针p仍然指向那块字符串。

而当我们执行完printf函数之后,发现指针p变为野指针了。
这是因为,我们所称为的函数出代码块销毁其实并不是真的销毁,而只是使得该代码块变得可以被覆盖,所以当出func函数时,可以发现func并没有销毁,而当执行printf时会发现p变为了野指针,这是由于printf也是函数,printf函数覆盖了func函数。
返回值临时变量接收的本质是什么呢?我们再来看一段代码
#pragma warning(disable:4996)
#include <stdio.h>
#include <Windows.h>
int func() {
int n = 1;
return n;
}
int main()
{
int num = func();
printf("%d\n", num);
system("pause");
return 0;
}
有一个问题就衍生了,当func返回之后,该函数就会被销毁,变量n也就会销毁,那返回后,用num接收时会接收到n中的1吗?

查看反汇编时,可以看到,func返回时,会将返回的值存到一个通用寄存器eax中,而用num接收时,会将eax中的值再放入num中。
那如果我们不使用num接收会发生什么呢?
#pragma warning(disable:4996)
#include <stdio.h>
#include <Windows.h>
int func() {
return 1;
}
int main()
{
func();
system("pause");
return 0;
}

可以发现,我们无论接收不接收,只要函数返回这个整型值,就会把该值存入寄存器中。
也就是说,当我们接收,就会使用这个寄存器。不接收,就不使用寄存器。但是返回值一定会存到寄存器中。
const关键字也许应该被替换为readonly
const修饰的只读变量

可以看到,被const修饰过的变量,不能直接被修改,那是否可以间接被修改呢?

虽然有警告,但是我们是可以进行修改的。
所以,const修饰的变量并不是真的不可被修改的常量
那么const修饰变量的意义在哪里呢?
- 让编译器进行直接修改式检查
给变量加上const之后,就告知了编译器此变量不可以被修改,而如果在某个地方此变量被修改了,那么编译器就报错,也就是说,加上了const就告诉了编译器不能被修改,而如果被修改了你就报错提醒用户。
- 告诉其他程序员(正在改你代码或者阅读你代码的)这个变量后面不要改哦。也属于一种“自描述”含义
给变量加上const之后,就告诉其它用户,此变量不要被修改,如果你修改了就报错提醒用户。
const修饰的变量,可以作为数组定义的一部分吗?

很显然是不可以的,即使你变量n被const修饰了,它仍然还是变量,只不过是不能直接被修改而已。
const只能在定义的时候直接初始化,不能二次赋值。为什么?

很简单,因为不能直接对变量n进行修改嘛,那么二次赋值当然也是不可以的了。
case语句后面是否可以是const修饰的变量呢?

很显然,也是不可以的!
我们一般称const修饰的变量为只读变量,因为该变量在意义上是不允许被修改的,只是用来读取的。
const修饰一般变量
一般变量是指简单类型的只读变量。这种只读变量在定义时,修饰符const可以用在类型说明符前面,也可以用在后面。
//demo
const int a = 5;
int const b = 10;
const修饰数组
//demo
const int arr1 = {
0,1,2,3,4 };
int const arr2 = {
5,6,7,8,9 };
当然了,数组的元素也是不允许直接被修改的

const修饰指针
const int* p; //p指向的内容不可以被修改,但是p本身可以被修改
int const* p; //p指向的内容不可以被修改,但是p本身可以被修改
int* const p; //p指向的内容可以被修改,但是p本身不可以被修改
const int* const p; //p指向的内容和p本身都不可以被修改
有一个方法就能很好的记忆以上四种情况
若const在*的左边,则指针指向的内容不可以被修改
若const在*的右边,则指针本身不可以被修改
const修饰函数的参数

看上面的show函数,它的功能就只是用来输出字符串,所以为了防止show函数可能会改变字符串,咱们加上一个const限定符修饰,如果字符串被改变了编译器报警,加上const也是为了告诉其他用户不要修改字符串。

其实加与不加const,对该函数的影响并不是特别的大,而是我们身为程序员在编写代码时,要尽可能考虑清楚该段代码可能存在哪些问题,从而使用一些手段来解决这些问题或者是告诉我们出现了问题!const就是一个典型的例子,我们为了防止某个变量改变,从而加上const修饰。
const修饰函数的返回值

该函数的返回值加上了const,意思是不想通过返回值改变n的大小,而如果把返回值赋值给一个没有const修饰的指针,该指针是可以修改n的大小的,这就违背了该函数的意愿。所以编译器警告了。
这样子的话,就不会出现警告,并且也不能通过返回值改变n的大小,也符合了该函数的意愿。
对了,对于一般的内置类型,加const是无意义的,因为一般内置类型本身就是临时拷贝,return之后该函数就销毁了。加上const的意义又何在呢?
看下面的图片,可以出一个规律

在C语言中,一个变量限定等级低的赋值给等级高的,一般不会警告。而等级高的赋值给等级低的,一般就会警告。
这也很容易理解,对于变量a来说,我们让它变得相对更安全一点,而变量b安全性会变得更差,也违背了b不想被修改的意愿。
最易变的关键字 - volatile

先看while函数,很明显是一个死循环
它的正常执行流程是cpu中的寄存器从内存中读取到pass中的值,然后进行逻辑判断,执行空语句,再次循环从内存中读取……
但是,cpu可能会对while函数做出优化,优化方案现在理解就是直接将pass中的值放入寄存器中,不再从内存中读取,每次循环直接逻辑判断,执行,逻辑判断执行……,所以万一当pass中的值发生修改使得while不再死循环时,这时cpu并不会从内存中读取新的值,使得每次逻辑判断的时候永远都是寄存器中的值。
而volatile就是解决这个问题的,给pass加上volatile之后,使得该函数在优化之后,仍然是每次从内存中读取,这样就会使得万一当pass发生变化时,寄存器中的值也能及时发生改变。
的值放入寄存器中,不再从内存中读取,每次循环直接逻辑判断,执行,逻辑判断执行……,所以万一当pass中的值发生修改使得while不再死循环时,这时cpu并不会从内存中读取新的值,使得每次逻辑判断的时候永远都是寄存器中的值。
而volatile就是解决这个问题的,给pass加上volatile之后,使得该函数在优化之后,仍然是每次从内存中读取,这样就会使得万一当pass发生变化时,寄存器中的值也能及时发生改变。
边栏推荐
- Innovative lampblack supervision in the management measures for the prevention and control of lampblack pollution in Deyang catering service industry (Draft for comments)
- Tupu software intelligent wind power: operation and maintenance of digital twin 3D wind turbine intelligent equipment
- NLP-D58-nlp比赛D27&刷题D14&读论文&mathtype
- 三维向量场中的通量
- A person even ran a Weibo app
- Revit API:明细表 ViewSchedule
- Cvpr2019/ image translation: transgaga: geometry aware unsupervised image to image translation
- MySQL导致索引失效的情况详解
- Multi store drug inventory system source code large chain drugstore management system source code
- 推荐4个Flutter重磅开源项目
猜你喜欢

2018/GAN:Self-Attention Generative Adversarial Networks自我注意生成对抗网络

Embedded interface review materials

泰勒公式及常用展开

AutoCAD -- summarize three methods of drawing rounded corners in CAD

高仿書旗小說 Flutter 版,學起來

Visual explanation of clockwise inner curve in Green's formula hole digging method

Startup process analysis of APP performance optimization

2018/gan:self attention generating adversarial networks

smart-doc + Torna 兼容版本

再来一个高仿开眼的短视频APP
随机推荐
The lower left corner of vs QT VTK displays the synchronized minor coordinate axis
接私活必备的 6 个开源项目
不容错过 | 华为内部资料--成功的项目管理PPT(123页)
生成式对抗网络(GANs)及变体
Dot and cross product
【HackTheBox】 meow
推荐4个Flutter重磅开源项目
Generate all possible binary search trees
不同物体使用同一材质,有不同的表现
开口式霍尔电流传感器助力直流配电改造
A cartoon reading app highly imitating Tencent comics
生成所有可能的二叉搜索树
Recommend 4 flutter heavy open source projects
Stm32-------adc (voltage detection)
docker 部署redis
Leetcode——链表笔试题
Different objects use the same material and have different performances
高仿书旗小说 Flutter 版,学起来
三维向量场中的通量
What is the same origin policy?