const只读变量:

  • const修饰的变量是只读的,本质还是一个变量
  • const修饰的局部变量在栈上分配空间
  • const修饰的全局变量在全局函数区分配资源空间
  • const只在编译器有用,在运行期无用

注意:const修饰的变量不是真的常量,他只是告诉编译器该变量不能出现在赋值符号的左边

const全局变量的分歧:

  • 在现代C语言编译器中,修改const全局变量将导致程序崩溃
  • 标准C语言编译器不会将const修饰的全局变量存贮于只读存贮区中,而是存贮可修改的全局数据区,其值依然可以改变

程序实例1:

  1. #include <stdio.h>
  2.  
  3. const int g_cc = ;
  4.  
  5. int main()
  6. {
  7. const int cc = ;
  8.  
  9. int* p = (int*)&cc;
  10.  
  11. printf("cc = %d\n", cc);
  12.  
  13. *p = ;
  14.  
  15. printf("cc = %d\n", cc);
  16.  
  17. p = (int*)&g_cc;
  18.  
  19. printf("g_cc = %d\n", g_cc);
  20.  
  21. *p = ; //error
  22.  
  23. printf("g_cc = %d\n", g_cc);
  24.  
  25. return ;
  26. }

这段代码说明,const修饰的局部变量可以使用指针修改,但是const修饰全局变量不可以通过指针进行修改,第21行代码试图修改const修饰全局变量,由于我使用的codeblocks,是一款现代编译器,所以编译阶段会报错,删掉21行代码程序就可以正常运行

const的本质:

  • C语言的const使得变量具有只读属性
  • 现代C编译器中的const将具有全局生命周期的变量存贮于只读存贮区
  • const不能顶第一真正意义上的常量

程序示例2:

  1. #include <stdio.h>
  2.  
  3. const int g_array[] = {};
  4.  
  5. void modify(int* p, int v)
  6. {
  7. *p = v;
  8. }
  9.  
  10. int main()
  11. {
  12. int const i = ;
  13. const static int j = ;
  14. int const array[] = {};
  15.  
  16. modify((int*)&i, ); // ok
  17. modify((int*)&j, ); // error
  18. modify((int*)&array[], ); // ok
  19. modify((int*)&g_array[], ); // error
  20.  
  21. printf("i = %d\n", i);
  22. printf("j = %d\n", j);
  23. printf("array[0] = %d\n", array[]);
  24. printf("g_array[0] = %d\n", g_array[]);
  25.  
  26. return ;
  27. }

第3行和第13行声明了用const修饰的具有全局生命周期的变量,所以在试图用指针来修改他们的值的时候,编译器会报错

const修饰函数参数和返回值:

  • const修饰函数参数表示在函数体内不希望改变参数的值
  • const修饰函数返回值表示返回值不可改变,多用于返回指针的情形
  • 小贴示:C语言的字符串字面量存贮于只读存贮区中,在程序中需要使用const char* 指针

程序实例3:

  1. #include <stdio.h>
  2.  
  3. const char* f(const int i)
  4. {
  5. i = ;
  6.  
  7. return "Delphi Tang";
  8. }
  9.  
  10. int main()
  11. {
  12. char* pc = f();
  13.  
  14. printf("%s\n", pc);
  15.  
  16. pc[] = '_';
  17.  
  18. printf("%s\n", pc);
  19.  
  20. return ;
  21. }

这段代码是错误的,但是我们来剖析一下,首先编译的时候第5行会出错,我们注释掉,接下来再编译,在12行会给出一个警告,我们用一个char *类型来接受了一个字面值常量,因为只是警告,所以我们可以运行一下,最后运行的时候还是出错了,因为第16行尝试修改了一个字面值常量

深藏不露的volatile:

  • volatile 可以理解为  “编译器警告指示”
  • volatile 告诉编译器必须每次去内存中去该变量值
  • volatile 主要修饰可能被多个线程访问的变量
  • volatile 也可以修饰可能被未知因数更改的变量

示例程序4:

  1. int boj = ; //编译器在编译的时候发现obj
  2.  
  3. int a=;
  4. int b=;
  5.  
  6. a= obj; //“聪明“的编译器不会到内存中去找obj对应的值,而是直接替换为10
  7.  
  8. sleep(); //在另一个线程里面可能已经改变了obj的值
  9.  
  10. b= obj; //这个时候编译器还是自作聪明的用10来代替obj,而不去内存中去找obj对应的值

这段代码只是一个小的片段,但是已经可以帮助我们理解有的时候编译器的自作聪明可能会导致某些bugconst volatile int i = 0;但是如果在定义一个变量的时候我们加上volatile属性,编译器每次就会去内存中去找到变量对应的值。

小结:

  • const 使得变量具有只读属性
  • const 不能定义真正意义上的常量
  • const将具有全局生命周期的变量存贮于只读存贮区
  • volatile 强制编译器减少优化,必须每次从内存中取值

C语言进阶——const 和 volatile 分析09的更多相关文章

  1. 第9课 - const 和 volatile分析

    第9课 - const和volatile分析 1. const只读变量 (1)const修饰的变量是只读的,本质上还是变量,并不是真正意义上的常量         ※※ const只是告诉编译器该变量 ...

  2. 第9课 const和volatile分析

    1. const只读变量——(注意不是真正常量,只是告诉编译器不能出现在赋值号左边!) (1)const修饰的变量是只读的,本质还是变量 (2)const修饰的局部变量在栈上分配空间 (3)const ...

  3. const和volatile分析

    c语言中const修饰的变量是只读的,不能直接作为赋值号的左值,其本质还是变量:会占用内存空间:本质上const在编译器有用,运行时无用(还是可以通过指针改变它的值) ; int *p=&ab ...

  4. C语言进阶——enum, sizeof, typedef 分析11

    枚举类型的使用方法: enum是C语言的 一种自定义类型 enum值是可以根据需要自定义的整型值 第一个enum的值默认为0 默认情况下的enum值是在前一个定义值的基础上加 1 enum类型的变量只 ...

  5. C语言进阶——struct和union分析10

    struct的小秘密: C语言中的struct可以看作变量的集合 struct的问题:空结构体占用多大内存呢? 程序实例1: #include <stdio.h> struct TS { ...

  6. 《C语言进阶剖析》课程目录

    <C语言进阶剖析>学习笔记                                                         本文总结自狄泰软件学院唐佐林老师的<C语言 ...

  7. C语言-const和volatile深度分析

    1.const只读变量 const修饰的变量是只读的.本质还是变量 const修饰的局部变量在栈上分配空间 const修饰的全局变量在全局数据区分配空间 const只在编译期有用,在运行期无用 con ...

  8. C语言中关键字auto、static、register、const、volatile、extern的作用

    原文:C语言中关键字auto.static.register.const.volatile.extern的作用 关键字auto.static.register.const.volatile.exter ...

  9. 【R笔记】R语言进阶之4:数据整形(reshape)

    R语言进阶之4:数据整形(reshape) 2013-05-31 10:15 xxx 网易博客 字号:T | T 从不同途径得到的数据的组织方式是多种多样的,很多数据都要经过整理才能进行有效的分析,数 ...

随机推荐

  1. ssh配置解释

    http://vbird.dic.ksu.edu.tw/linux_server/0310telnetssh_2.php /etc/ssh/sshd_config Port 29922 #Addres ...

  2. Lubuntu , ubuntu 搜索文件

    使用命令行方式搜索 $ locate your_filename

  3. Windows Host 文件

    Windows XP Home / Windows 7/ Windows Server 2008 c:\windows\system32\drivers\etc\hosts 如果碰到Localhost ...

  4. word文档快速转换为PPT演示文稿

    方法一: 访问http://t.im/pdftoppt,点击继续浏览(会跳转至:https://smallpdf.com/cn/pdf-to-ppt): 打开word文档,设置为“横向”,输出为PDF ...

  5. Linux上mariadb数据库(博客初学者使用测试)

    MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可.MariaDB由MySQL的创始人麦克尔·维德纽斯主导开发,他早前曾以10亿美元的价格,将自己创建的公司M ...

  6. win8下使用IIS服务器及自定义服务器端包含模块(SSI)步骤

    配置完过段时间就容易忘记,特此记录. 1.开启IIS服务器. 默认没有安装,需要先安装. 打开控制面板--> 打开“程序和功能”--> 左侧选择“启用或关闭windows功能”--> ...

  7. jQuery实现轮播切换以及将其封装成插件(3)

    在前两篇博文中,我们写了一个普通的轮播切换.但是我们不能每一次需要这个功能就把这些代码有重新敲一次.下面我们就将它封装成一个插件. 至于什么是插件,又为什么要封装插件,不是本文考虑的内容.  我们趁着 ...

  8. Java关键字transient和volatile小结

    转自:http://heaven-arch.iteye.com/blog/1160693 transient和volatile两个关键字一个用于对象序列化,一个用于线程同步,都是Java中比较高阶的话 ...

  9. JS无限添加HTML到指定位置

    用JS把HTML添加到指定位置有两种写法,一种是用字符串,一种是用javascript中的方法 第一种: 用字符串写 <h2>利用JS无限添加一个相同部分</h2> <h ...

  10. js字符串内容包含单引号‘’和双引号“”怎么办?

    如果javascript中的字符串包含单引号和双引号,可以用转义字符来标识 'I\'m \"OK\"!'; 表示的字符串内容是:I'm "OK"! 转义字符\可 ...