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 ",cc); cc = 3; printf("cc = %d ",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 ",cc); *p = 3; printf("cc = %d ",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 ",g_cc); g_cc = 4; printf("g_cc = %d ",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 ",g_cc); int* p = (int*)&g_cc; *p = 4; printf("g_cc = %d ",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 ",i); printf("j = %d ",j); printf("array[0] = %d ",array[0]); printf("g_array[0] = %d ",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 ",i); printf("j = %d ",j); printf("array[0] = %d ",array[0]); printf("g_array[0] = %d ",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 ",pc); pc[4] = '_'; printf("%s ",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 ",pc); pc[4] = '_'; printf("%s ",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 ",pc); pc[4] = '_'; printf("%s ",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;
- 编译器在编译的时候发现