1. 先看如下代码
  2. #include <stdio.h>
    #include <string.h> #define ARRSIZE(a) (sizeof(a)/sizeof(a[0]))
    int main()
    {
    const int i = 10;
    int *p = (int *)&i;
    int a[i];
    *p = 100; printf("%d\n", ARRSIZE(a));
    printf("%d\t%d\n", i, *p);
    return 0;
    }
    我用gcc编译运行,上面这段简单的代码的输出结果是:
    100               # 这也是一个很奇怪的结果。
    100    100

    这个结果说明了2个问题,1:可以用const变量作为数组大小;2:可以修改const变量的值。

    但难道真是这样吗?又或者说,难道在不同机器,不同编译器下都这样吗?

    并不尽然,首先这个程序在VC编译器下,不能通过,VC编译器不允许用const变量作为数组大小。
    即使把有关数组的给删掉,VC编译后的可执行文件不能执行,发生内存错误。这说明不可以修改const变量。

    因此这个是与编译器有关的。

    下面要思考的是:为什么gcc编译器能允许这事发生,而VC不允许。
    对上面的代码略做修改,将const int i = 10放到main函数外面去。
    #include <stdio.h>
    #include <string.h> #define ARRSIZE(a) (sizeof(a)/sizeof(a[0]))
    const int i = 10;
    int main()
    {
    int *p = (int *)&i;
    int a[i]; printf("%d\n", ARRSIZE(a));
    *p = 100;
    printf("%d\t%d\n", i, *p);
    return 0;
    }
    这时gcc编译通过,运行出现段错误。段错误是经典错误,表明访问了不该访问的段。
    因此这说明全局的const变量不能修改;局部的const能修改。

    作如下推测:
    gcc下,全局的const变量存储于只读的数据段,因此肯定不能修改。
    局部的const存储在堆栈段,堆栈段是可读可写的;因此不能避免程序员去修改const。

    虽然局部const在堆栈,且堆栈可写,但如下方式却行不通:
    const int i = 10;
    i = 100;        # 这里的错误是编译错误。
    因此编译器不允许你对局部const变量[直接]修改,它能够识别你在修改const变量。
    但正如前面的程序,你只要将局部const变量的地址赋给指针,就能骗过编译器了。
    而在VC下,const变量总是在只读数据段里。

    这时再来看数组
    #include <stdio.h>
    #include <string.h> #define ARRSIZE(a) (sizeof(a)/sizeof(a[0]))
    const int i = 10;
    int a[i]; // 将数组拿到main的外面来
    int main()
    {
    printf("%d\n", ARRSIZE(a));
    return 0;
    }
    这时会有编译错误:error: variably modified ‘a’ at file scope
    如果将"int a[i]"放到main函数里,则正确。

    我还不太清楚这样的具体原因。这里我只能大致得出结论是:不能用const变量来作为数组大小。
    至于为什么将"int a[i]"放到main函数里时没有错误,我并不清楚,我看了下汇编码,发现gcc对这种情况进行了一些特殊的处理,并不是简单的分配堆栈空间,但更细致的原因,我并未深入研究。

    另外在VC下,是不能用const变量来作为数组大小的,不管是局部还是全局的const。

    因此不要试着去修改const变量,也不要用const变量来作为数组大小

C中const 定义常量的使用的更多相关文章

  1. php中const定义常量

    const 常量 1.在定义时必须被初始值,2.前面不加任何修饰符3.变量名字母一般都大写4.常量可以被子类继承5.一个常量是属于一个类的,而不是某个对象的 作用:当某些值是固定不变的,就用const ...

  2. PHP中define()和const定义常量的区别

    在PHP中可以通过define()和const两种方式定义常量可是在开发中我们应该什么时候用define()定义常量,什么时候用const定义常量? 这两种方式定义常量的主要区别是什么? 从5.3版本 ...

  3. 在php中define和const定义常量的区别

    define和const都可以用来定义常量,但是const定义常量的时候大小写敏感,而define可以通过设置第三个参数为true的时候来取消大小写敏感! 如图: 引用地址:点这里

  4. PHP 中 define() 和 const 定义常量时的区别

    自 PHP 5.3.0 起,有两种方式定义常量,使用 const 关键字或者 define() 函数:   1 2 const FOO = 'BAR'; define('FOO', 'BAR'); 这 ...

  5. C++ —— 非类中使用const定义常量的初始化,以及#define和typedef的区别

    总结一下在非类中使用const关键字定义常量时的初始化问题,亲测VS2015.顺便记录#define宏和typedef的区别. 1 首先对const声明的常量的初始化做简单小结: , w2 = , w ...

  6. 为什么很多人使用#define而不是const定义常量

    众所周知,C语言一开始只有#define,C程序员用#define定义符号常量.但后来ANSI C加入了const限定符,而const应该比#define更好,为什么现在的C程序员还在大量使用#def ...

  7. iOS define 宏定义 和 const定义常量区别

    const   const 是c++中的修饰符.  c++中常用来定义常量,修饰左值. #define 宏定义语句, 在预处理阶段直接做文本替换,不做类型检查. 它们之间的最大区别: 1.  对于co ...

  8. 关于java中接口定义常量和类定义常量的区别

    /** * * @author YZJ * @Description java中定义常量的最佳方法 */ public final class Contants{ /** * @Description ...

  9. js 中const 定义的值是否能更改

    const定义的基本类型不能改变,但是定义的对象是可以通过修改对象属性等方法来改变的. 1. const aa=trueaa=falseconsole.log(aa)VM1089:2 Uncaught ...

随机推荐

  1. Linux Kernel 代码艺术——编译时断言【转】

    转自:http://www.cnblogs.com/hazir/p/static_assert_macro.html 本系列文章主要写我在阅读Linux内核过程中,关注的比较难以理解但又设计巧妙的代码 ...

  2. 写好shell脚本的13个技巧【转】

    有多少次,你运行./script.sh,然后输出一些东西,但却不知道它刚刚都做了些什么.这是一种很糟糕的脚本用户体验.我将在这篇文章中介绍如何写出具有良好开发者体验的 shell 脚本. 产品的最终用 ...

  3. centos6.5系统bash损坏之救援模式修复

    1.模拟bash被损坏的情况 # mv /bin/bash /tmp [root@localhost ~]# sync [root@localhost ~]# shutdown -r now 2.挂载 ...

  4. centos重启报错Umounting file systems:umount:/opt:device is busy

    系统重启报错: Umounting file systems:umount:/opt:device is busy 只能硬关机,回想一下最近刚安装了nod32 for linux x64的杀毒软件,开 ...

  5. dell r720服务器raid5安装centos6.5系统

    服务器型号R720 已经配置好了raid,需要安装centos6.5系统 1.开机,按F10,进入系统引导界面,选择加载系统选项,并选择redhat 6.7选项 系统提示不支持,选择仍然继续,根据提示 ...

  6. javascript 练习题目答案

    //廖雪峰的博客的这个教程的答案//https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb300 ...

  7. Annoy 近邻算法

    Annoy 随机选择两个点,以这两个节点为初始中心节点,执行聚类数为2的kmeans过程,最终产生收敛后两个聚类中心点 二叉树底层是叶子节点记录原始数据节点,其他中间节点记录的是分割超平面的信息 但是 ...

  8. winform(记事本--查找)

  9. javascript this详解(转)

    在面向对象编程语言中,对于this关键字我们是非常熟悉的.比如C++.C#和Java等都提供了这个关键字,虽然在开始学习的时候觉得比较难,但只要理解了,用起来是非常方便和意义确定的.JavaScrip ...

  10. Git 将项目(代码)从GitHub上克隆(下载)到本地仓库

    要将项目从GitHub上克隆到本地,首先你得下载并安装好git for window. 配置Git: 1.安装完后,右键单击桌面空白处,选择Git Gui Here,进去之后,选择左上角的help选项 ...