一、const, static与volatile
1、CONST
const的用法(定义和用途):Const就是常量修饰符, const 变量应该在声明的时候就进行初始化,如果在声明 常量的适合没有提供值,则该常量的值是不确定的,且无法修改。
const 修饰主要用来修饰变量、函数形参和类成员函数:
1)const 常量:定义时就初始化,以后不能更改。
2)const 形参: func(const int a);该形参在函数里不能改变
3)const 修饰类成员函数:该函数对成员变量只能进行只读操作,就是 const类成员函数是不能修改成员变量的数值的。
基本作用:const
用于定义常量,如果一个变量被 const
修饰,那么它的值就不能再被改变。
修饰:函数参数与修饰函数返回值
当 const 关键字修饰函数的参数和返回值时,作用同样是防止修改。
修饰:函数参数
在传值调用时,const 修饰参数表示防止修改参数的值。
在传址调用时,const 修饰参数的具体意义根据该参数具体是常量指针还是指针常量或是指向常量的常量指针有所不同。
常量指针作为参数是防止在函数中修改其指向常量的值,例如:char *strcpy(char *dest, const char *src);
假如定义该函数时,修改参数 src 的指向地址中的值,编译器就会报错。指针常量作为参数,是防止在函数中修改其指向的地址,例如:void swap ( int * const p1 , int * const p2 )
假如在定义该函数时,修改了参数 p1 和 p2 所指向的地址,编译器就会报错。指向常量的常量指针作为参数,既是防止在函数中修改其指向的地址,也是防止在函数中修改其指向地址中的值。
修饰:函数返回值
与 const 修饰参数时的作用相同,区别在于表示的是返回值的某些特性不可修改。
修饰:全局变量与修饰局部变量
这里的区别在于,const 修饰局部变量和全局变量时,该变量所存储的区域有所区别
修饰:全局变量
当 cost 修饰全局变量时,该变量会被存放在内存的常量区,而非一般全局变量所在的静态全局区。
修饰:局部变量
当 const 修饰局部变量时,该变量会被存放在内存的栈区,当该函数执行完毕时,该变量所占用的内存会被回收释放。
2、STATIC
const的用法(定义和用途):
在 C 语言中, static作用:“改变生命周期”或者“改变作用域”。有以下特性 :
1、static局部变量:局部变量为动态存储,即指令执行到定义处才分配内存,将 一个变量声明为函数的局部变量, 使其变为静态存储方式(静态数据区), 那么这 个局部变量在函数执行完成之后不会被释放,而是继续保留在内存中。
2 、 static 全局变量: 全局变量即定义{}外面,其本身就是静态变量 ,编译时就分配内存,这只会改变其连接方式,使其只在本文件内部有效,而其他文件不可连接或引用该变量。
3、static 函数:对函数的连接方式产生影响,使得函数只在本文件内部有效, 对其他文件是不可见的。这样的函数又叫作静态函数。使用静态函数的好处是, 不用担心与其他文件的同名函数产生干扰,另外也是对函数本身的一种保护机 制。如果想要其他文件可以引用本地函数,则要在函数定义时使用关键字 extern, 表示该函数是外部函数,可供其他文件调用。另外在要引用别的文件中定义的外 部函数的文件中,使用 extern声明要用的外部函数即可。
基本作用:static
可以修饰局部变量,全局变量或者函数,改变其作用域或存储位置。
为变量进行初始化
用 static 修饰的变量,会被自动初始化,对应的内存空间中,会被 0 值填充。
static 所修饰的局部变量不在存储在栈区,而是存储在静态全局区。
3、VOLATILE
volatile的含义:volatile的本意是“易变的”。在程序执行过程中,访问寄存器通常要比访问内存单元快得多。因此,编译器往往会进行优化,以减少对内存的存取次数,但这有可能导致读取到脏数据。
volatile的作用:当使用volatile声明变量时,系统会确保每次都需要从该变量所在的内存地址重新读取数据,即使前面的指令刚刚从该地址读取过数据。换句话说,遇到这个关键字声明的变量时,编译器将不会对访问该变量的代码进行优化,从而保证了对该特殊地址的稳定访问。如果不使用volatile,编译器则可能会对相关的代码进行优化
3.1 在C语言中,volatile
关键字是一种类型修饰符,用于告诉编译器不应对该变量的访问进行优化,以确保每次访问都是从内存中直接读取数据,而不是从缓存或寄存器中读取。
3.2 在嵌入式开发中,使用 volatile
关键字是非常常见的,它常用于以下几种情况:
中断服务程序中的变量:当一个变量在中断服务程序(ISR)中被修改,并且这个变量的值需要被主程序或其他程序检测时,应该使用 volatile 关键字。这是因为中断可能在任何时间发生,而编译器优化可能会使得主程序无法正确地读取到最新的变量值。
多任务环境下的共享标志:在多任务环境中,不同任务之间可能需要通过某些共享的标志来进行通信。这些标志应该被声明为 volatile,以确保每次访问都是直接从内存中读取最新值,而不是从缓存或寄存器中获取可能已经过时的值。
存储器映射的硬件寄存器:对于映射到特定硬件寄存器的变量,它们可能在任意时刻由硬件异步修改。volatile 可以确保对这类变量的每次读写都会直接与硬件寄存器交互,防止编译器进行不恰当的优化。这样可以确保每次读写操作都不会被编译器优化掉,从而保证程序能够正确地与硬件设备通信。
此外,volatile 关键字的作用是防止编译器对于被修饰的变量进行错误的优化。由于嵌入式系统通常涉及到实时性要求很高的操作,如中断处理和硬件控制,因此确保变量的每次访问都是最新的值至关重要。
在嵌入式开发中,正确使用 volatile 关键字对于确保系统的可靠性和稳定性是非常重要的。它帮助开发者避免因编译器优化而导致的潜在问题,确保程序能够准确地反映硬件状态和执行预期的操作。
二、总结
const
- 定义和用途:
const
是常量修饰符,用于声明一个变量的值在初始化之后不能被修改。 - 主要用法:
- 修饰变量:定义时就初始化,之后不能更改。
- 修饰函数形参:表示在函数内不能修改该参数的值。
- 修饰类成员函数:表明该函数不会修改类的任何成员变量(常成员函数)。
- 修饰指针:区分常量指针(指针指向的内容不可变)和指针常量(指针本身不可变)。
- 修饰函数返回值:表明返回值的某些特性不可修改(如返回指向常量的指针)。
- 存储位置:
- 修饰局部变量时,存储在栈区。
- 修饰全局变量时,存储在常量区(与普通全局变量存储于静态全局区不同)。
static
- 定义和用途:
static
用于改变变量的生命周期或作用域,或者改变函数的连接属性。 - 主要用法:
- 修饰局部变量:延长局部变量的生命周期,使其在函数调用结束后依然保留在内存中。
- 修饰全局变量:限制全局变量的作用域,使其只在定义它的文件内部可见。
- 修饰函数:限制函数的连接属性,使其只在定义它的文件内部可调用。
- 初始化:被
static
修饰的变量会自动初始化为0(对于数值类型和指针)。 - 存储位置:无论修饰局部变量还是全局变量,
static
变量都存储在静态存储区。
volatile
- 定义和用途:
volatile
告诉编译器该变量的值可能会以编译器难以预测的方式被改变,因此每次访问该变量时都必须直接从其内存地址中读取,而不能使用缓存中的值。 - 主要用法:
- 用于中断服务程序中被修改的变量,确保主程序能读取到最新值。
- 用于多任务环境中的共享标志,确保各任务间通信的可靠性。
- 用于存储器映射的硬件寄存器,确保每次读写都直接与硬件交互。
- 作用:防止编译器对变量的访问进行优化,确保程序的实时性和准确性,特别是在嵌入式系统和硬件交互密集的场景中。
综上const, static与volatile,分别用于确保数据的不可变性(const
)、控制变量的生命周期和可见性(static
),以及确保变量访问的实时性和准确性(volatile
)。