6 const 和 volatile
1 const 定义一个只读变量,而不是常量
-
const修饰的变量是只读的,其本质还是变量const修饰的变量不是真正的常量,它只是告诉编译器该变量不能出现在赋值符号的左边 -
const修饰的局部变量在栈上分配空间;const修饰的全局变量在全局数据区分配空间,所以const修饰的变量在内存中是分配了空间的,那么就可以修改这个空间里的值 -
const只在编译期对编译器有用,在运行期无用,即可以修改所修饰的变量的值
2 const 全局变量的分歧
-
在现代C语言编译器中,
const全局变量存储于只读存储区,修改const全局变量将导致程序崩溃 -
在标准C语言编译器中不会将
const修饰的全局变量存储于只读存储区,而是存储于可修改的全局数据区,所以其值可以改变 -
示例1:
const修饰局部变量 => read-only variable,不可直接修改-
Demo
#include <stdio.h> int main() { //const修饰的局部变量,即所谓的“常量” const int cc = 1; printf("cc = %d\n",cc); cc = 3; printf("cc = %d\n",cc); return 0; } -
GCC 编译
test1.c: In function 'main': test1.c:9: error: assignment of read-only variable 'cc'
-
-
示例2:
const修饰局部变量,可利用指针修改-
Demo
#include <stdio.h> int main() { //const修饰的局部变量,即所谓的“常量” const int cc = 1; int* p = (int*)&cc; printf("cc = %d\n",cc); *p = 3; printf("cc = %d\n",cc); return 0; } -
GCC 编译
cc = 1 cc = 3
-
-
示例3:
const修饰全局变量,read-only variable-
Demo
#include <stdio.h> //const 修饰全局变量 const int g_cc = 2; int main() { printf("g_cc = %d\n",g_cc); g_cc = 4; printf("g_cc = %d\n",g_cc); return 0; } -
GCC 编译
test3.c: In function 'main': test3.c:10: error: assignment of read-only variable 'g_cc'
-
-
示例4:利用指针修改
const修饰的全局变量-
Demo
#include <stdio.h> //const 修饰全局变量 const int g_cc = 2; int main() { printf("g_cc = %d\n",g_cc); int* p = (int*)&g_cc; *p = 4; printf("g_cc = %d\n",g_cc); return 0; } -
GCC 编译通过,运行出错!
g_cc = 2 段错误 -
BCC 运行
g_cc = 2 g_cc = 4
-
3 const 的本质
-
C语言中的
const使得变量具有只读属性 -
现代C编译器中
const将具有全局生命周期的变量(全局生命周期的变量有:全局变量,static 修饰的局部变量)存储于只读存储区,其值不可改变 -
const不能定义真正意义上的常量,只是一个只读变量
-
示例5:修改被
const修饰的具有全局生命周期的变量-
Demo
#include <stdio.h> //const 修饰的普通全局数组,其中每个元素都为只读变量 const int g_array[5] = {0}; void modify(int* p,int v) { *p = v; } int main() { const int i = 0; // const 修饰的普通局部变量 const static int j = 0; // const 修饰的 static 局部变量 const int array[5] = {0}; // const修饰的普通局部数组 modify((int*)&i,1); // ok modify((int*)&j,2); // error modify((int*)&array[0],3); // ok modify((int*)&g_array[0],4); // error printf("i = %d\n",i); printf("j = %d\n",j); printf("array[0] = %d\n",array[0]); printf("g_array[0] = %d\n",g_array[0]); return 0; } -
编译运行
段错误 -
注释18,20行
#include <stdio.h> //const 修饰的普通全局数组,其中每个元素都为只读变量 const int g_array[5] = {0}; void modify(int* p,int v) { *p = v; } int main() { const int i = 0; // const 修饰的普通局部变量 const static int j = 0; // const 修饰的 static 局部变量 const int array[5] = {0}; // const修饰的普通局部数组 modify((int*)&i,1); // ok //modify((int*)&j,2); // error modify((int*)&array[0],3); // ok //modify((int*)&g_array[0],4); // error printf("i = %d\n",i); printf("j = %d\n",j); printf("array[0] = %d\n",array[0]); printf("g_array[0] = %d\n",g_array[0]); return 0; } -
编译运行
i = 1 j = 0 array[0] = 3 g_array[0] = 0
-
4 const 修饰函数参数和返回值
-
const修饰函数参数表示在函数体内不希望改变参数的值 -
const修饰函数返回值表示返回值不可改变,多用于返回指针的情形 -
C 语言中的字符串字面量存储于只读存储区中,在程序中需要使用
const char*指针来指向 -
示例:字符串字面量
-
Demo1:利用
char*指向一个字符串字面量,错误行为!#include <stdio.h> const char* f(const int i) { i = 5; //error return "ABCD EFG"; } int main() { char* pc = f(0); printf("%s\n",pc); pc[4] = '_'; printf("%s\n",pc); return 0; } -
编译
test.c: In function 'f': test.c:5: error: assifnment of read-only location 'i' test.c: In fuction 'main': test.c:11: warning: initialization discards qualifiers from pointer target type -
Demo2
#include <stdio.h> const char* f(const int i) { return "ABCD EFG"; } int main() { char* pc = f(0); printf("%s\n",pc); pc[4] = '_'; printf("%s\n",pc); return 0; } -
编译
test.c: In fuction 'main': test.c:11: warning: initialization discards qualifiers from pointer target type -
运行
ABCD EFG 段错误 -
Demo3:利用
const char*接收函数的返回值,不可修改#include <stdio.h> const char* f(const int i) { return "ABCD EFG"; } int main() { const char* pc = f(0); printf("%s\n",pc); pc[4] = '_'; printf("%s\n",pc); return 0; } -
编译
test.c: In fuction 'main': test.c:14: error: assignment of read-only location '*(pc+4u)'
-
5 volatile 关键字
-
volatile可理解为“编译器警告指示字” -
volatile告诉编译器必须每次去内存中取变量值 -
volatile主要修饰可能被多个线程访问的变量 -
volatile也可以修饰可能被未知因数更改的变量 -
示例
- 编译器在编译的时候发现
obj没有被当作左值使用,因此会直接将obj替换成 10,而把 a 和 b 都赋值为 10 - 如果暂停 100ms,在这段时间内很可能
obj变量这段内存空间很可能被线程所改变,那么 b 所得到的值就不应该是 10 了 - 这种情况下,应该用
volatile修饰obj变量
int obj = 10; int a = 0; int b = 0; a = obj; sleep(100); b = obj; - 编译器在编译的时候发现

浙公网安备 33010602011771号