learn_C_deep_2 (作用域和生命周期、局部变量和全局变量、最宽宏大量的关键字 - auto、最快的关键字 - register)

简介: learn_C_deep_2 (作用域和生命周期、局部变量和全局变量、最宽宏大量的关键字 - auto、最快的关键字 - register)

作用域和生命周期


作用域:  -   影响范围问题  -  该变量的有效区域


指的是变量或函数在程序中可以被访问的范围。变量或函数的作用域可以是全局的或局部的。全局作用域中的变量或函数对于整个程序都是可见的,而局部作用域中的变量或函数只对包含它们的代码块或函数可见。


生命周期:  -  存在时间长短问题  -  时间的概念,什么时候被开辟,什么时候被释放


       指的是对象或变量从创建到销毁的过程。一个对象或变量的生命周期可以是静态的,也可以是动态的。静态的生命周期是指对象或变量在程序运行期间一直存在,而动态的生命周期是指对象或变量在某个特定的时刻创建或销毁。


作用域和生命周期的区别:


1. 定义和意义不同:作用域是指变量、函数或对象在程序中可见的范围,对于不同类型的变量或对象,其作用域可能不同。而生命周期则是指变量或对象存在的时间,从创建到销毁的整个过程。

2. 管理方式不同:作用域是编译时确定的,即在程序编译时就可以确定一个变量或对象的作用域。而生命周期则是运行时确定的,需要在程序执行过程中管理变量或对象的生命周期。

3. 影响不同:作用域主要影响变量或对象的可见性和访问权限,即决定了在哪些地方可以访问变量或对象。而生命周期则主要影响的是变量或对象所占用的内存空间,以及资源的分配和释放等方面。


局部变量和全局变量


       在程序中,变量的作用域可以分为全局变量和局部变量两种类型。


代码块:


       代码块(也叫语句块)是由一对大括号`{}`包围的一段代码,它可以包含多条语句,被视为一个整体。在C语言中,代码块通常用于以下几个场景:


1. 作为函数体:函数的代码块包含了函数的所有语句,用于定义函数的执行流程。

2. 作为控制语句的执行体:例如if语句、for语句、while语句、switch语句等,它们的执行体就是一个代码块。

3. 作为变量的作用域:代码块内定义的变量只在代码块内有效,超出代码块的范围就无法访问。


例如,下面是一个简单的代码块示例:


#include <stdio.h>

int main()

{

 int a = 10;

       {

               int b = 20;

               printf("a + b = %d\n", a + b);

       }

//printf("%d\n", b); // 错误:变量b不在作用域内

return 0;

}


在这个示例中,代码块包含了两个变量a和b,其中变量b只在代码块内有效,超出代码块的范围就无法访问了。由于代码块具有作用域的特性,它可以被用来控制变量的访问权限,从而提高程序的安全性和可维护性。


全局变量:


       全局变量是指在程序的任何地方都可以被访问到的变量,程序中定义的全局变量具有全局作用域,即程序的任何地方都可以使用该变量,并且它们在程序结束前一直存在。全局变量通常在程序的开头定义,例如:


#include <stdio.h>

int global_variable = 10; // 全局变量

int main()

{

       printf("global_variable = %d\n", global_variable);

       return 0;

}


局部变量:


       局部变量是指在一个函数、语句块或其他限定域内定义的变量,它只能在该函数、语句块或限定域内被使用,超出这个范围就不能访问了,也就是具有局部作用域。例如:


#include <stdio.h>

int main()

{

       for (int i = 0; i < 5; i++)

       {

               printf("%d\n", i);

       }

       return 0;

}


在这个例子中,i是在main函数中定义的局部变量,只能在for循环中使用,超出for循环的范围就无法使用了。


全局变量和局部变量的区别


1. 作用域不同:全局变量的作用域是整个程序,可以被程序中的所有函数访问和使用;而局部变量的作用域仅限于定义它的函数、语句块或其他限定域。


2. 生命周期不同:全局变量在程序启动时被创建,在程序结束时被销毁,因此它们的生命周期与整个程序的运行周期相同;而局部变量则随着函数、语句块或其他限定域的结束而自动销毁,因此它们的生命周期比全局变量短。


3. 访问权限不同:全局变量可以被程序中的所有函数访问和使用,因此容易受到误操作或非法访问的威胁;而局部变量只能在其定义的函数、语句块或其他限定域内访问,因此更安全。


4. 存储位置不同:全局变量在程序的静态数据区中分配内存,而局部变量在函数的栈中分配内存。


最宽宏大量的关键字 - auto


       一般在代码块中定义的变量,即局部变量,默认都是auto修饰的,不过我们一般都省略不写。默认所有的变量都是auto吗?不是,一般用来修饰局部变量。局部变量(局部变量、自动变量、临时变量都是一回事)


       在 C 语言中,auto 关键字被用来显式声明具有自动存储类型的变量,也就是说通过使用 auto 关键字声明的变量,在函数内部都具有自动存储类型,它们的生命周期与函数的调用周期相同。当程序从函数退出时,自动存储类型的变量也随之“销毁”,其空间也就被释放。


        在 C 语言中,变量默认是具有“自动存储类型”的。使用 auto 关键字显式声明该变量的存储类型为自动是多余的,因此在 C 语言中使用 auto 关键字是不必要的。但是它的用法如下:


auto int g_val = 0;//error:全局范围的声明不能包含此存储类

#include<stdio.o>

int main()

{

       auto int a = 5;

       //等价于int a = 5;

       return 0;

}


在上述代码中,使用了 auto 关键字来显式地声明变量 a 为自动存储类型。


最快的关键字  -  register


存储金字塔


       其实,CPU主要是负责进行计算的硬件单元,但是为了方便运算,一般第一步需要先把数据从内存读取到CPU内,那么也就需要CPU具有一定的数据临时存储的能力。注意:CPU并不是当前要计算了,才把特定数据读取到CPU里面,那样速度太慢了。所以现代CPU内,都集成了一组叫做寄存器的硬件,用来做临时数据的保存。


寄存器的认识


       在计算机中,寄存器是一种高速数据存储设备,通常是CPU内部的一组硬件电路,能够在CPU内部快速访问数据和执行指令。与内存相比,寄存器的速度更快,因为它们通常被直接嵌入到CPU芯片中,并且只在CPU内部使用。 寄存器的主要功能包括:


1. 存储CPU指令执行时需要访问的数据和地址信息;

2. 存储函数调用时需要保存的返回地址、函数参数等信息;

3. 存储程序计数器(program counter,PC)等CPU内部的控制信息;

4. 存储其他需要经常访问的数据,如计数器、标志位等。


       寄存器的数量和功能取决于CPU架构和型号。有些CPU内部只有几个寄存器,而有些则具有大量的寄存器,可以提高程序的执行效率。 在编程中,程序员可以使用汇编语言或特殊的编译指令来直接访问寄存器,并将数据存储到寄存器中。由于寄存器速度快,因此在编程时,程序员通常会尽量使用寄存器来存储频繁使用的数据,以提高程序的执行速度。


寄存器存在的本质


       寄存器存在的本质是为了提高计算机程序的执行效率。计算机程序在执行时需要频繁地进行数据读取、计算和存储等操作,这些操作需要通过内存、缓存等存储设备来完成,而这些设备的访问速度都较慢,会导致程序执行的瓶颈。


       为了提高程序的执行速度,计算机设计师开发了寄存器这种高速缓存来存储计算过程中需要频繁访问的数据和地址信息,以减少对内存等存储设备的访问次数,从而提高程序的执行效率。使用寄存器可以减少数据在不同存储设备之间的传输和转换时间,使程序能够更快地执行。


register修饰变量


       在编程语言中,register是一种关键字,用于指示编译器将变量存储到寄存器中。由于寄存器的访问速度非常快,因此将变量存储在寄存器中,可以提高程序的执行效率,特别是对于需要频繁访问的变量,效果更加明显。


       虽然使用register关键字可以告诉编译器将变量存储在寄存器中,但实际上是否能够实现将变量存储在寄存器中,取决于编译器和CPU的具体实现。在现代计算机系统中,由于寄存器数量有限,而且被其他数据存储到寄存器中的可能性很高,因此编译器通常会根据需要动态地选择哪些变量应该存储到寄存器中。 需要注意的是,由于寄存器是CPU内部的缓存,它的容量非常有限,因此在使用register关键字时,应该权衡使用寄存器和使用内存之间的差异,并根据实际情况进行适当的选择,以达到最优的执行效率。另外,register关键字只是给编译器一种提示,实际存储的位置还取决于编译器和CPU的实现,因此不能保证所有的变量都能够存储在寄存器中。


总结上面:register修饰的变量就是尽量将所修饰的变量放入CPU寄存去中,从而达到提高效率的目的。


register可以修饰的变量


       在C语言中,只有自动存储类的变量(即局部变量)可以使用register关键字进行修饰,因为静态存储类的变量和全局变量已经被编译器自动优化过了,而且寄存器数量已经足够满足程序的需求。


注意:


1.局部的变量(全局变量和静态变量会导致CPU寄存器被长时间占用)


2.不会被写入内存的(写入就需要写回内存,后续还要读取检测的话,register就没必要使用了)


3.高频被读取的(提高效率所在)


4.如果要使用,请不要大量使用,因为寄存器的数量有限


5.由于register修饰的变量存储在寄存器中,不能进行&操作,因为地址是内存相关的概念


#include<stdio.h>

int main()

{

   register int pass = 0;

   printf("%d", pass);

   printf("%p", &pass);//error:寄存器变量上的"&"

   return 0;

}


相关文章
|
12天前
学习使用register定义变量的方法
【6月更文挑战第19天】学习使用register定义变量的方法。
7 1
|
2月前
|
存储 数据可视化 编译器
learn_C_deep_1 (C程序补充知识、变量的声明和定义、声明和定义的区别)
learn_C_deep_1 (C程序补充知识、变量的声明和定义、声明和定义的区别)
|
2月前
|
Python
Day4作用域,Python关键字global和nonlocal使用
作用域,Python关键字global和nonlocal使用
10 0
|
2月前
|
JavaScript 前端开发
js开发:请解释什么是作用域(scope),并说明全局作用域、局部作用域和块级作用域的区别。
JavaScript中的作用域规定了变量和函数的可见性与生命周期。全局作用域适用于整个脚本,变量可通过全局对象访问,可能导致命名冲突和内存占用。局部作用域限于函数内部,每次调用创建新作用域,执行完毕后销毁。ES6引入的块级作用域通过`let`和`const`实现,变量仅在其代码块内有效,并有暂时性死区。作用域机制有助于代码组织和变量管理。
31 1
|
2月前
|
算法 C语言 C++
【C/C++ 关键字 类型限定符 】 C/C++ 中 const的用法:限制变量的作用域和可见性
【C/C++ 关键字 类型限定符 】 C/C++ 中 const的用法:限制变量的作用域和可见性
24 0
|
2月前
|
存储 安全 编译器
【C++】引用、内联函数、auto关键字等
【C++】引用、内联函数、auto关键字等
|
12月前
|
存储 安全 算法
02-📝C++核心语法|C++对C的扩展【::作用域运算符、名字控制、struct类型加强、C/C++中的const、引用(reference)、函数】
复习`C++核心语法`,且适当进行汇编探索底层实现原理,进一步夯实基础,为以后的`底层开发`、`音视频开发`、`跨平台开发`、`算法`等方向的进一步学习埋下伏笔。
02-📝C++核心语法|C++对C的扩展【::作用域运算符、名字控制、struct类型加强、C/C++中的const、引用(reference)、函数】
|
Go
go04 变量和作用域
go04 变量和作用域
48 0
|
C语言
C 中的变量作用域 – 局部和全局作用域解释
C 中的变量作用域 – 局部和全局作用域解释
|
Go Python
Go-变量与常量详解(声明、初始化、匿名变量、作用域等)
Go-变量与常量详解(声明、初始化、匿名变量、作用域等)
71 0
Go-变量与常量详解(声明、初始化、匿名变量、作用域等)