欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C语言之volatile、static、const、extern

程序员文章站 2024-02-29 18:17:58
...

C语言之volatile、static、const、extern

1.volatile

1.1 volatile基本含义

volatile是一个类型修饰符(type specifier),是被设计用来修饰被不同线程访问和修改的变量;volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接到内存中读值。
volatile防止代码被编译器优化,例如:

a=1;
a=2;
a=3;

编译器会进行优化,优化为只有a=3(即忽略前三条语句,只产生一条机器代码);如果键入volatile,则编译器会逐一地进行编译并产生相应的机器代码(产生四条代码)
volatile声明的变量是时刻都有可能变的,例如:volatile int a;a*a并不一定是a的平方。

1.2 volatile常见用途

volatile变量的几个例子:

1)并行设备的硬件寄存器(如:状态寄存器)

2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

3)多线程应用中被几个任务共享的变量

1.3 volatile常见提问

1.一个参数既可以是const还可以是volatile吗?
可以的,例如只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
2.一个指针可以是volatile 吗?
可以,当一个中服务子程序修该一个指向一个buffer的指针时。

2 static

2.1 static基本含义

static关键字主要用于定义全局静态变量、局部静态变量、静态函数。

2.2 static 全局静态变量

全局静态变量:当一个进程的全局变量被声明为static之后,它的中文名叫静态全局变量。静态全局变量和其他的全局变量的存储地点并没有区别,都是在.data段(已初始化)或者.bss段(未初始化)内,但是它只在定义它的源文件内有效,其他源文件无法访问它。

2.3 static 局部静态变量

普通的局部变量在栈空间上分配,这个局部变量所在的函数被多次调用时,每次调用这个局部变量在栈上的位置都不一定相同。局部变量也可以在堆上动态分配,但是记得使用完这个堆空间后要释放之。
static局部变量中文名叫静态局部变量。它与普通的局部变量比起来有如下几个区别:
1.位置:静态局部变量被编译器放在全局存储区.data(注意:不在.bss段内,原因见3)),所以它虽然是局部的,但是在程序的整个生命周期中存在。
2.访问权限:静态局部变量只能被其作用域内的变量或函数访问。也就是说虽然它会在程序的整个生命周期中存在,由于它是static的,它不能被其他的函数和源文件访问。
3.值:静态局部变量如果没有被用户初始化,则会被编译器自动赋值为0,以后每次调用静态局部变量的时候都用上次调用后的值。这个比较好理解,每次函数调用静态局部变量的时候都修改它然后离开,下次再调用该函数,读的时候从全局存储区读出的静态局部变量就是上次修改后的值。
需要注意的是由于static局部变量的这种特性,使得含静态局部变量的函数变得不可重入,即每次调用可能会产生不同的结果。这在多线程编程时可能会成为一种隐患。需要多加注意。

2.4 static函数

static函数的作用域是本源文件,static函数可以很好地解决不同原文件中函数同名的问题,因为一个源文件对于其他源文件中的static函数是不可见的。

参考:https://zhuge.blog.csdn.net/article/details/76850375

3 const

3.1 const基本含义

const-英文意思-常量,它限定了一个变量时不允许被修改,可以产生静态作用,使用const在一定程度上可以提高程序的安全性和可靠性。

3.2 const 与 #define

预处理指令 #define xxx 可以很方便的进行值替代,这种值替代至少在3个方面有点突出,一是避免意义模糊的数字出现,使得程序语意流畅清晰,二是可以很方便的进行参数的调整与修改,只需要在宏定义那修改,整个程序中所有引用该宏定义的地方都随之更改。三是提高了程序的执行效率,由于是使用“预编译器”进行值替代,并不需要为这些常量存储空间,所以执行效率高。

说道这里,可能会迷惑以上这些内容与const有什么关系呢?

预处理语句虽然有上面说的有点,但是它也有缺点,即预处理语句仅仅只是简单的值替代,缺乏“类型”检测机制,这样预处理语句就不能享受编译系统的类型检查好处了,从而可能成为引发一系列错误的隐患,比如在程序中,定义一个只读变量“u8 name[]=“tom”,在编程中如果对name[1]进行赋值,可能就会引起一系列的错误。

所以,const的推出的初始目的,正是为了取代预编译指令,消除它的缺点,同事继承它的优点。

const作用及优点:

1.以const修饰的常量值,具有不可变性,这是它能取代预定义语句的基础。

2.很明显,它也同样可以避免意义模糊的数字出现,可以很方便的进行参数的调整和修改。

3.C/C++编译器通常不会为const变量分配RAM存储空间,而是将他们保存在符号表中,这就使得它成为了一个编译期间的常量,没有了存储与读内存操作,使得它的效率很高,同时,这也是它取代预定义的重要基础,编译器在编译它时,不会去读存储的内容,而是直接从符号表中替代。这是一种特别特别特别好的优点,比如在存放字库或者图片库时,这些库的对应的数组体积会特别大。

3.3 const常见用途

3.3.1 const常量

由于常量一旦被创建后其值就不能再改变,所以常量必须在定义的同时赋值(初始化),后面的任何赋值行为都将引发错误。

3.3.2 const与指针

const 也可以和指针变量一起使用,这样可以限制指针变量本身,也可以限制指针指向的数据。const 和指针一起使用会有几种不同的顺序,如下所示:
const int *p1;
int const *p2;
int * const p3;
在最后一种情况下,指针是只读的,也就是 p3 本身的值不能被修改;在前面两种情况下,指针所指向的数据是只读的,也就是 p1、p2 本身的值可以修改(指向不同的数据),但它们指向的数据不能被修改。

当然,指针本身和它指向的数据都有可能是只读的,下面的两种写法能够做到这一点:
const int * const p4;
int const * const p5;
const 离变量名近就是用来修饰指针变量的,离变量名远就是用来修饰指针指向的数据,如果近的和远的都有,那么就同时修饰指针变量以及它指向的数据。

3.3.3 const与函数形参

在C语言中,单独定义 const 变量没有明显的优势,完全可以使用#define命令代替。const 通常用在函数形参中,如果形参是一个指针,为了防止在函数内部修改指针指向的数据,就可以用 const 来限制。例如:int strcmp ( const char * str1, const char * str2 );

3.3.4 const 和非 const 类型转换

当一个指针变量 str1 被 const 限制时,并且类似const char *str1这种形式,说明指针指向的数据不能被修改;如果将 str1 赋值给另外一个未被 const 修饰的指针变量 str2,就有可能发生危险。因为通过 str1 不能修改数据,而赋值后通过 str2 能够修改数据了,意义发生了转变,所以编译器不提倡这种行为,会给出错误或警告。
const char *和char *是不同的类型,不能将const char *类型的数据赋值给char *类型的变量。但反过来是可以的,编译器允许将char *类型的数据赋值给const char *类型的变量。
char *指向的数据有读取和写入权限,而const char *指向的数据只有读取权限,降低数据的权限不会带来任何问题,但提升数据的权限就有可能发生危险。

4 extern

4.1 extern含义

extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。此外extern也可用来进行链接指定。
extern有两个作用:
第一个,当它与"C"一起连用时,如: extern “C” void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的。
第二,当extern不与"C"在一起修饰变量或函数时,如在头文件中: extern int g_Int; 它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块活其他模块中使用,记住它是一个声明不是定义。

4.2 extern 和 static

(1) extern 表明该变量在别的地方已经定义过了,在这里要使用那个变量.
(2) static 表示静态的变量,分配内存的时候, 存储在静态区,不存储在栈上面.
static 作用范围是内部连接的关系, 和extern有点相反.它和对象本身是分开存储的,extern也是分开存储的,但是extern可以被其他的对象用extern 引用,而static 不可以,只允许对象本身用它. 具体差别首先,static与extern是一对“水火不容”的家伙,也就是说extern和static不能同时修饰一个变量;其次,static修饰的全局变量声明与定义同时进行,

相关标签: C和指针