【C语言】关键字

文章详细介绍了C语言中const、volatile和static三个关键字的用法和特点。const用于创建只读变量,限制数据的修改权限;volatile则防止编译器优化,确保每次访问变量都从内存获取最新值,适用于多线程或中断等场景;static主要改变变量的作用域和生存期,使局部变量保持状态或限制全局变量的作用范围。
摘要由CSDN通过智能技术生成


前言

传统的c语言(ANSI C)有32个关键字
在这里插入图片描述
1999年12月16日,ISO推出了C99标准,该标准新增了5个C语言关键字:
在这里插入图片描述
2011年12月8日,ISO发布C语言的新标准C11,该标准新增了7个C语言关键字:
在这里插入图片描述
下面将对部分关键字进行总结

一、const

const就是常量的意思,用它修饰变量后,该变量就变成只读的了,也就是说const功能的本质就是降低数据操作权限。

特别注意:由于const修饰后变量的值就不可以修改了,因此需要在定义的时候就初始化完毕

1、修饰局部变量

正常情况下修改局部变量的值:

#include <stdio.h>
int main()
{
	int n=5;
	printf("%d\n",n);
	n=10;
	printf("%d\n",n);
	return 0;
}
5
10

如果加了const后,直接通过变量名修改就会出错:

#include <stdio.h>
int main()
{
	const int n=5;
	printf("%d\n",n);
	n=10;
	printf("%d\n",n);
	return 0;
}

在这里插入图片描述

就没办法修改被const修饰的局部变量了吗?

也是有办法的:

#include<stdio.h>

int main()
{
	const int i = 10;//将i定义为局部变量
	printf("before modication: i=%d\n",i);
	int *p = &i;
	*p = 20;
	printf("after modification:i= %d\n",i);

	return 0;
}
before modication: i=10
after modification:i= 20

通过变量名的方式不行,通过解引用的方式就行。

但会给出一个警告:
[Warning] initialization discards ‘const’ qualifier from pointer target type

2、修饰全局变量

跟上面不一样,当我们试图通过任何方式去修改const修饰的全局变量,程序都会出错崩溃。

#include<stdio.h>

const int i = 10;//将i定义为全局变量
int main()
{
	printf("before modication: i=%d\n",i);
	int *p = &i;
	*p = 20;
	printf("after modification:i= %d\n",i);

	return 0;
}
before modication: i=10
段错误

3、常量指针和指针常量

(1)const修饰指针(常量指针)

像诸如

int a=10;
int b=20;
const int *p= &a;

常量指针的名称可以从定义过程看出:

const(常量) int *(指针)p= &a;

常量指针的特点是:指针p的指向可以改,指针p指向的值不可以改。

这句话怎么理解呢?

指针的指向可以改,即我可以重新定义p的指向:

p = &b;

指向的值不可以改,即下面的操作是不允许的:

*p = 20;

怎么记忆呢?
常量指针,常量在前(既是说名字中常量在前面,也是说常量指针的定义过程const在前),因此指针p指向的值不可以改。

虽然不能通过解引用的方式更改指针指向的值,但可以直接通过变量名修改,这点跟局部变量一样:

#include<stdio.h>

int main()
{
	int a = 10;
	const int *p = &a;
	printf("before modication: a=%d\n",*p);
	a=20;
	printf("after modification:a= %d\n",*p);

	return 0;
}

before modication: a=10
after modification:a= 20

(2)const修饰常量(指针常量)

像诸如

int a =10;
int b =20;
int *const p =&a;

指针常量的名称也可以从定义过程看出:

int *(指针)const(常量) p =&a;

指针常量的特点是:指针p的指向不可以改,指针p指向的值可以改。

这句怎么理解呢?
p的指向不能改,因此下面的代码是错的:

p=&b;

p指向的值可以改,因此我可以改a的值:

*p = 20;

怎么记忆呢?
指针常量,指针在前(既是说名字中指针在前面,也是说指针常量的定义过程指针在前),因此指针p的指向不可以改。

(3)const既修饰指针又修饰常量

像诸如

int a = 10;
const int* const p = &a;

此时指针p的指向和指向的值都不可以改。

虽然无法通过解引用的方式修改指向的值,但可以通过变量名直接修改:

int a = 10;
const int *const p = &a;

*p = 20;//这是不允许的
a=20;//这是可以的

4、修饰函数形参

如果形参是一个指针,那么用const修饰该形参,就可以防止函数修改指针指向的数据。C语言标准库中就有很多函数的形参被const限制,如常见的strlen:

size_t strlen ( const char * str );

当看到这样的函数,就是在告诉你函数不会修改你提供的字符串,请你放心。当然除了防止函数修改字符串,也会阻止程序员修改字符串。

5、修饰函数返回值

这点后面再补充。

二、volatile

这个关键字的有道解释如下:
在这里插入图片描述

1、一句话总结功能

可以防止变量被编译器优化,导致数据更新被忽视

2、编译器优化是什么?

首先了解一个大背景

众所周知,内存的访问速度是远小于CPU的处理速度的,为了让内存不拖后腿,提升计算机整体运算速度,可以从三个方面入手:

(1)硬件层面:引入高速缓存Cache,它的访问速度比内存快
(2)软件层面:
程序员编写执行高效的代码,这对程序员的水平要求较高;
还有就是编译器对代码进行编译优化。

编译优化是怎么进行的呢?

我们看一个例子:

int a,b,c;
a=1;
b=a;
c=a;

这段代码转化为汇编的话执行过程如下

int a,b,c;//申请内存 **************************步骤1
a=1;//将1先存入CPU寄存器***********************步骤2
    //将寄存器保存的值存入内存(地址为&a)******步骤3
b=a;//将内存&a位置的数据存入CPU寄存器***********步骤4
    //将CPU寄存器中保存的数据存入内存的&b位置***步骤5
c=a;//将内存&a位置的数据存入CPU寄存器***********步骤6
    //将CPU寄存器中保存的数据存入内存的&c位置****步骤7

可以发现步骤4和6是重复执行的,步骤6可以省略,即被优化掉,这就是编译优化。

3、被优化后会带来什么问题?

省略步骤6后,c读取a的值就不是从内存中读取,而是从寄存器中读取,读取的就是上一步临时保存的值。
那假如在执行

b=a;
c=a;

过程中,刚好执行完b=a,a就变了怎么办?

再从寄存器中读取之前保存的值就读取错误了,数据没有更新!

这就是被优化后的隐患。

4、什么情况下会导致a的值突然发生变化?

(1)中断
执行完b=a,一个中断过来,在中断服务函数中将a改变
(2)多线程
能力不够,待定
(3)硬件寄存器
硬件寄存器的值会根据的硬件的状态随时变化

这些情况下要避免存储变量被编译器优化!

5、用volatile关键字解决上述问题

在变量定义时加上volatile关键字,就是告诉编译器这个变量随时会变,不允许优化,每次存取该变量都要从内存中去存取而不是使用之前在寄存器中的备份。

三、static

1、static修饰局部变量

结果会使局部变量的生存期变长,变为静态存储期。

2、static修饰全局变量或者函数

结果会使其链接属性从外部链接属性变为内部链接属性,只能当前文件访问,其他文件无法访问

关于以上两点,我在【C语言】从空间和时间两个角度看一个变量
这篇文章中已经做了详细总结。

三、答疑

1、define为什么不是C语言关键字?

define是编译器的预编译指令,是编译器实现的,不是C语言的内容。

2、特别说明,关于存储类型和特征修饰

volatile和const属于特征修饰关键字,static属于存储类型关键字,c语言定义变量的完整格式为

存储类型 特征修饰 数据类型 变量名

存储类型有5种(auto,static分为修饰局部和全局,extern,register),特征修饰就是 volatile或const

3、定义常量的方式?

C语言中有两种定义常量的方式:
(1)使用#define

#define LENGTH 10   

(2)使用const

const int length= 10;

那const和#define有什么区别呢?

const具有类型检查和作用域的优势,而 #define 仅进行简单的文本替换,可能会导致一些意外的问题。因此通常情况下,建议使用 const 关键字来定义常量。


4、C语言中变量和常量本质上的区别?

依照我现在的理解,两者本质上的区别就是前者有写权限,后者没有写权限。

参考资料

1、https://www.bilibili.com/video/BV1VN4y1c7w9/?spm_id_from=333.337.search-card.all.click&vd_source=53d27d53fc6ff276be6e93437afd3e0e
2、http://blog.csdn.net/xingjiarong/article/details/47282255
3、《带你学C带你飞》
4、http://c.biancheng.net/view/2041.html
5、https://www.runoob.com/cprogramming/c-constants.html
6、https://blog.csdn.net/water_3700348/article/details/78054277
5、https://blog.csdn.net/ZhaDeNianQu/article/details/120157469

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值