Summary
1)const润饰的变量是只读的,实质还是变量
。(不管值是否扭转)
2)调配空间
:
const润饰的局部变量在栈上调配空间
。
const润饰的全局变量在全局数据区调配空间
。(这两点印证了const润饰的依然是变量,因为在内存中仍然会调配空间
)
3)const只在编译期有用,在运行期无用。(示意:const润饰的变量,在编译的时候不能放在赋值符号左侧
,然而在运行期,就能够通过指针扭转该变量的值
)
4)在古代C语言编译器中,批改const全局变量会导致程序解体
。因为古代C语言编译器,会将具备全局生命期的const变量放在只读存储区
,改了只读存储区的内容,造成解体。规范C语言编译器依然将全局生命期的const变量放在全局数据区,所以是能够扭转的。
5)const润饰函数参数,示意在函数体内不心愿扭转参数的值
(形参不能够呈现在赋值符号左侧
)。
6)const润饰函数返回值,示意返回值不可扭转
,多用于返回指针的状况(指针指向的值不可扭转
)。
7)字符串字面量
存储于只读存储区
,必须应用const char*
来援用字符串字面量(这样在编译期会将批改只读存储区字面量的谬误报进去);如果只是应用了char *
,此时编译的过
,然而运行时就会遇到段谬误
。
8)volatile通知编译器每次都必须去内存中去变量值
;volatile多用于多线程
环境中(变量可能在其余线程或其余中央被扭转)
const和volatile
1、const
1.1 const润饰变量
const int const_global_i = 1; // const全局变量,全局生命期int main(){ const static int const_static_i = 2; // static局部变量,全局生命期 const int const_local_i = 3; // 一般局部变量 // const_local_i = 30; // error,在编译期不容许呈现在赋值符号左侧 int* p = NULL; // 规范C语法须要将要应用的变量先申明。 p = (int*)&const_global_i; *p = 10; printf("const_global_i = %d\n", const_global_i); p = (int*)&const_static_i; *p = 20; printf("const_statici = %d\n", const_static_i); p = (int*)&const_local_i; *p = 30; printf("const_local_i = %d\n", const_local_i); return 0;}
- 在bcc编译器下(
规范C语言编译器
),这段代码可失常编译,测试的后果为三个变量的值均被扭转,阐明,在规范C编译器下,const定义的所有只读变量的值都能够扭转
。 在gcc编译器下(扩大C编译器),这段代码能够编译的过,然而上面这两处赋值语句,在运行时都会产生
段谬误
。阐明,在古代C语言编译器下
,const定义
的只读变量如果是全局生命期(如全局变量、static变量)
,则会将该变量放到只读存储区
,批改了就会段谬误。p = (int*)&const_global_i; *p = 10; printf("const_global_i = %d\n", const_global_i); p = (int*)&const_static_i; *p = 20; printf("const_statici = %d\n", const_static_i);
1.2 const润饰函数参数
const润饰函数参数示意在函数体内不心愿扭转参数的值
。
void func(const int a){ a = 2; // error, assignment of read-only parameter ‘a’}
当应用const润饰了函数参数,在函数外部就不能扭转形参的值。
非凡的:当函数的参数是指针时
,const
仍然在爱护某个值不可扭转
,遵循“左数右指”
准则。
void func(const int* a){ *a = 1; // error,指向的数不可扭转,即*a不能作为左值}void func(int* const a){ a = (int*)1; // error,指针不可扭转,即a不可作为左值}
1.3 const润饰函数返回值
const润饰函数返回值示意返回值不可扭转
,多用于返回指针
的情景。
const int* GetInt(){ int* p = (int*)malloc(4); *p = 1; return p;}int main(){ const int* p = GetInt(); // 返回值为const的指针,也必须const的指针来接 // 在编译层面保障函数返回的指针指向的值不可扭转 printf("*p = %d\n", *p); *p = 2; // error,批改只读的值,read-only return 0;}
多用于函数返回值是指针
的情景,是因为,个别函数返回的这段内存,心愿是只读的,在哪都不容许扭转的。如果是一个一般的变量,函数返回的是一个正本
,也不存在批改原来的内存里的值
的状况。
1.4 字符串常量的类型?
C语言中的字符串字面量
存储于只读存储区
中,在程序中必须应用const char*
指针。
了解:字符串字面量存储于只读存储区中,天然在代码里,也须要应用const关键字来指明它的只读属性
。
// 谬误示例char* p = "Delphi"; // "Delphi"是一个字符串字面量,存储于只读存储区p[0] = 'a'; // runtime error,段谬误。批改只读存储区的天然会解体
// 正确用法:应用了const之后,谬误的赋值在编译期就会报进去const char* p = "Delphi"; // 应用const显示阐明"Delphi"字面量的只读属性p[0] = 'a'; // compile error,批改只读变量的值
2、volatile
- volatile可了解为“编译器正告批示字”,
禁止编译器优化
- volatile通知编译器
每次必须去内存中取变量值
- volatile次要润饰可能被
多个线程
拜访的变量 volatile也能够润饰可能被未知因素更改的变量
Demo示例int obj = 10;int a=0, b=0;a = obj;sleep(100);b = obj;
- 编译器在编译时发现obj
没有作为左值
应用,所以是不会扭转
的,那么就间接去拿他的字面量应用
了,不必去拜访内存了,多“聪慧”(因为CPU拜访内存是耗时的操作
,既然obj不变,所以拿字面量用也不会出错,而且更快了,两败俱伤)。 - 但实际上,如果这是一个
多线程程序
,或者是嵌入式中断处理程序
,在sleep的时候obj的值很可能在某个线程中或者某个中断处理程序中被扭转了,这时候间接用字面量的值就不对了。
- 编译器在编译时发现obj
- 所以是否应用volatile关键字,要
视状况剖析
,因为读内存是耗时的。
小问题:const voaltile int i = 0;变量i具备什么样的个性?编译器如何解决该变量?
答:const使得变量i具备只读属性,所以在程序中不可作为左值;volatile通知编译器每次遇到要用变量i时,都必须去读i所代表的那段内存里的值。
本文总结自“狄泰软件学院”唐佐林老师《C语言进阶课程》。
如有错漏之处,恳请斧正。