传统的c语言(ANSI C)有32个关键字
1999年12月16日,ISO推出了C99标准,该标准新增了5个C语言关键字:
2011年12月8日,ISO发布C语言的新标准C11,该标准新增了7个C语言关键字:
下面将对部分关键字进行总结
const就是常量的意思,用它修饰变量后,该变量就变成只读的了,也就是说const功能的本质就是降低数据操作权限。
特别注意:由于const修饰后变量的值就不可以修改了,因此需要在定义的时候就初始化完毕。
正常情况下修改局部变量的值:
#include
int main()
{
int n=5;
printf("%d\n",n);
n=10;
printf("%d\n",n);
return 0;
}
5
10
如果加了const后,直接通过变量名修改就会出错:
#include
int main()
{
const int n=5;
printf("%d\n",n);
n=10;
printf("%d\n",n);
return 0;
}
就没办法修改被const修饰的局部变量了吗?
也是有办法的:
#include
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
跟上面不一样,当我们试图通过任何方式去修改const修饰的全局变量,程序都会出错崩溃。
#include
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
段错误
像诸如
int a=10;
int b=20;
const int *p= &a;
常量指针的名称可以从定义过程看出:
const(常量) int *(指针)p= &a;
常量指针的特点是:指针p的指向可以改,指针p指向的值不可以改。
这句话怎么理解呢?
指针的指向可以改,即我可以重新定义p的指向:
p = &b;
指向的值不可以改,即下面的操作是不允许的:
*p = 20;
怎么记忆呢?
常量指针,常量在前(既是说名字中常量在前面,也是说常量指针的定义过程const在前),因此指针p指向的值不可以改。
虽然不能通过解引用的方式更改指针指向的值,但可以直接通过变量名修改,这点跟局部变量一样:
#include
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
像诸如
int a =10;
int b =20;
int *const p =&a;
指针常量的名称也可以从定义过程看出:
int *(指针)const(常量) p =&a;
指针常量的特点是:指针p的指向不可以改,指针p指向的值可以改。
这句怎么理解呢?
p的指向不能改,因此下面的代码是错的:
p=&b;
p指向的值可以改,因此我可以改a的值:
*p = 20;
怎么记忆呢?
指针常量,指针在前(既是说名字中指针在前面,也是说指针常量的定义过程指针在前),因此指针p的指向不可以改。
像诸如
int a = 10;
const int* const p = &a;
此时指针p的指向和指向的值都不可以改。
虽然无法通过解引用的方式修改指向的值,但可以通过变量名直接修改:
int a = 10;
const int *const p = &a;
*p = 20;//这是不允许的
a=20;//这是可以的
如果形参是一个指针,那么用const修饰该形参,就可以防止函数修改指针指向的数据。C语言标准库中就有很多函数的形参被const限制,如常见的strlen:
size_t strlen ( const char * str );
当看到这样的函数,就是在告诉你函数不会修改你提供的字符串,请你放心。当然除了防止函数修改字符串,也会阻止程序员修改字符串。
这点后面再补充。
可以防止变量被编译器优化,导致数据更新被忽视
首先了解一个大背景
众所周知,内存的访问速度是远小于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可以省略,即被优化掉,这就是编译优化。
省略步骤6后,c读取a的值就不是从内存中读取,而是从寄存器中读取,读取的就是上一步临时保存的值。
那假如在执行
b=a;
c=a;
过程中,刚好执行完b=a,a就变了怎么办?
再从寄存器中读取之前保存的值就读取错误了,数据没有更新!
这就是被优化后的隐患。
(1)中断
执行完b=a,一个中断过来,在中断服务函数中将a改变
(2)多线程
能力不够,待定
(3)硬件寄存器
硬件寄存器的值会根据的硬件的状态随时变化
这些情况下要避免存储变量被编译器优化!
在变量定义时加上volatile关键字,就是告诉编译器这个变量随时会变,不允许优化,每次存取该变量都要从内存中去存取而不是使用之前在寄存器中的备份。
结果会使局部变量的生存期变长,变为静态存储期。
结果会使其链接属性从外部链接属性变为内部链接属性,只能当前文件访问,其他文件无法访问
关于以上两点,我在【C语言】从空间和时间两个角度看一个变量
这篇文章中已经做了详细总结。
define是编译器的预编译指令,是编译器实现的,不是C语言的内容。
volatile和const属于特征修饰关键字,static属于存储类型关键字,c语言定义变量的完整格式为
存储类型 特征修饰 数据类型 变量名
存储类型有5种(auto,static分为修饰局部和全局,extern,register),特征修饰就是 volatile或const
C语言中有两种定义常量的方式:
(1)使用#define
#define LENGTH 10
(2)使用const
const int length= 10;
那const和#define有什么区别呢?
const具有类型检查和作用域的优势,而 #define 仅进行简单的文本替换,可能会导致一些意外的问题。因此通常情况下,建议使用 const 关键字来定义常量。
依照我现在的理解,两者本质上的区别就是前者有写权限,后者没有写权限。
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