const
来源:互联网 发布:淘宝在哪里领取优惠卷 编辑:程序博客网 时间:2024/05/01 11:57
1 const只读变量
- const修饰的变量是只读的,本质还是变量。
- const修饰的局部变量在栈上分配空间。
- const修饰的全局变量在全局数据区分配空间。
- const只在编译期有用,在运行期无用。
注意:const修饰的变量不是真的常量,它只是告诉编译器该变量不能出赋值符号的左边。
2 const全局变量的分歧
- 在现代C语言编译器中,修改全局变量将导致程序崩溃。
注意:标准C语言编译器不会将const修饰的全局变量存储于只读存储区,而是存储于可修改的全局数据区,其值依然可以改变。
编程实验:const变量的本质
#include <stdio.h>const int g_cc = 2;int main(){ const int cc = 1; int* p = (int*)&cc; printf("cc = %d\n", cc); *p = 3; printf("cc = %d\n", cc); p = (int*)&g_cc; // error printf("g_cc = %d\n", g_cc); *p = 4; printf("g_cc = %d\n", g_cc); return 0;}
3 const的本质
- C语言中的const使得变量具有只读属性。
- 现代C编译器中的const将具有全局生命周期的变量存储于只读存储区(包括全局变量和静态局部变量)。
- const不能定义真正意义上的常量。
需要注意的是:未初始化的具有全局生命周期的变量不会被储存到只读存储区,仍然被存储在全局数据区(.bss段),只有被初始化的具有全局生命周期的变量才会被储存到只读存储区。另外需要注意的一点是:对于
staitc const int a;
,a为全局变量或者静态变量。不能通过指向变量a的指针来更改a的值,a的值一直为0(实际在内存空间中的a的值已经被更改了,只是编译器将引用变量a的地方优化了,直接使用0而不是到内存中读取值。在定义变量时在前面加上voltile关键字即可强制编译器不要进行这种优化,每次引用变量a时都到内存中去读取相应的值)。对于const int a;
,a为全局变量,这种情况可以通过指向变量的a的指针来更改a的值。
0804841b <main>:#include <stdio.h>static const int g_a;int main(void){ 804841b: 8d 4c 24 04 lea 0x4(%esp),%ecx 804841f: 83 e4 f0 and $0xfffffff0,%esp 8048422: ff 71 fc pushl -0x4(%ecx) 8048425: 55 push %ebp 8048426: 89 e5 mov %esp,%ebp 8048428: 51 push %ecx 8048429: 83 ec 14 sub $0x14,%esp static const int a; int *p = (int*)&g_a; 804842c: c7 45 f4 24 a0 04 08 movl $0x804a024,-0xc(%ebp) *p = 123; 8048433: 8b 45 f4 mov -0xc(%ebp),%eax 8048436: c7 00 7b 00 00 00 movl $0x7b,(%eax) printf("*p = %d\n", *p); 804843c: 8b 45 f4 mov -0xc(%ebp),%eax 804843f: 8b 00 mov (%eax),%eax 8048441: 83 ec 08 sub $0x8,%esp 8048444: 50 push %eax 8048445: 68 50 85 04 08 push $0x8048550 804844a: e8 a1 fe ff ff call 80482f0 <printf@plt> 804844f: 83 c4 10 add $0x10,%esp printf("g_a = %d\n", g_a); // 从这里可以看到,编译器认为未初始化的静态全局只读变量的值就应该是0,而不去实际的内存中取值 8048452: b8 00 00 00 00 mov $0x0,%eax 8048457: 83 ec 08 sub $0x8,%esp 804845a: 50 push %eax 804845b: 68 59 85 04 08 push $0x8048559 8048460: e8 8b fe ff ff call 80482f0 <printf@plt> 8048465: 83 c4 10 add $0x10,%esp p = (int*)&a; 8048468: c7 45 f4 28 a0 04 08 movl $0x804a028,-0xc(%ebp) *p = 456; 804846f: 8b 45 f4 mov -0xc(%ebp),%eax 8048472: c7 00 c8 01 00 00 movl $0x1c8,(%eax) printf("*p = %d\n", *p); 8048478: 8b 45 f4 mov -0xc(%ebp),%eax 804847b: 8b 00 mov (%eax),%eax 804847d: 83 ec 08 sub $0x8,%esp 8048480: 50 push %eax 8048481: 68 50 85 04 08 push $0x8048550 8048486: e8 65 fe ff ff call 80482f0 <printf@plt> 804848b: 83 c4 10 add $0x10,%esp printf("a = %d\n", a); // 从这里可以看到,编译器认为未初始化的静态全局只读变量的值就应该是0,而不去实际的内存中取值 804848e: b8 00 00 00 00 mov $0x0,%eax 8048493: 83 ec 08 sub $0x8,%esp 8048496: 50 push %eax 8048497: 68 63 85 04 08 push $0x8048563 804849c: e8 4f fe ff ff call 80482f0 <printf@plt> 80484a1: 83 c4 10 add $0x10,%esp return 0; 80484a4: b8 00 00 00 00 mov $0x0,%eax}
实例分析:const的本质分析
#include <stdio.h>const int g_array[5] = {0};void modify(int* p, int v){ *p = v;}int main(){ int const i = 0; const static int j = 0; int const array[5] = {0}; 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;}
4 const修饰函数参数和返回值
- const修饰参数表示在函数体内不希望改变参数的值。
- const修饰函数返回值表示返回值不可改变,多用于返回指针的情况。
字符串的类型实际上是char*,因此赋值直接赋值给char*也是不会有警告或者错误的。
实例分析:const修饰函数参数与返回值
#include <stdio.h>const char* f(const int i){ i = 5; return "Delphi Tang";}int main(){ char* pc = f(0); printf("%s\n", pc); pc[6] = '_'; // Segmentation fault (core dumped) printf("%s\n", pc); return 0;}
注意:把const类型的指针复制给普通类型的指针会有警告:assignment discards ‘const’ qualifier from pointer target type,反过来则不会有警告。
5 小结
- cosnt使得变量具有只读属性。
- const不能定义真正意义上的常量。
- const将具有全局生命周期的变量存储于只读存储区。
阅读全文
1 0
- const
- const
- const
- CONST
- const
- const
- const
- const
- const
- const
- Const
- const
- const
- const
- CONST
- const
- const
- const
- java简单实例
- NumPy基础练习(练一遍搞定NumPy)
- ZigBee串口说明
- Python高级可视化库seaborn分布分析(基础整理)
- Python一些特别的语法
- const
- Hadoop学习(一)
- 数据结构实验之二叉树四:(先序中序)还原二叉树
- php_python远程调试
- MySQL安装以及常见的安装错误
- 连续总结第二十天
- oracle只导出建表语句,不导出表数据
- 单链表的基本运算实现代码标注
- Maven配置