• c和c++关于const的一些区别


    以下参考了网上的一些资料并通过程序验证。

    注意,以下情况都是用gcc和g++编译器得到的结果,用vs编译器又会有所不同。

    以下说下c和c++中const定义的常量的一些区别:

    c++中用const定义了一个常量后,不会分配一个空间给它,而是将其写入符号表(symbol table),这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。但是const定义的常量本质上也是一个变量,是变量就会有地址,那么什么时候会分配内存?看看下面的代码:

    复制代码
    int main(){
        const int a  = 2;
        int* p = (int*)(&a);
        *p = 30;
        cout<<&a<<endl; 
        cout<<p<<endl;  
        cout<<a<<endl;
        cout<<*p<<endl;
    }
    复制代码

    结果:

    我们看到,通过 int*p = (int*)(&a);这种方法,可以直接修改const常量对应的内存空间中的值,但是这种修改不会影响到常量本身的值,因为用到a的时候,编译器根本不会去进行内存空间的读取。这就是c++的常量折叠(constant folding),即将const常量放在符号表中,而并不给其分配内存。编译器直接进行替换优化。除非需要用到a的存储空间的时候,编译器迫不得已才会分配一个空间给a,但之后a的值仍旧从符号表中读取,不管a的存储空间中的值如何变化,都不会对常量a产生影响。

    但是在c中却不是这样.c没有constant folding的概念,用constant定义一个常量的时候,编译器会直接开辟一个内存空间存放该常量。不会进行优化。同样的例子在c下面会产生不同的结果:

    复制代码
     1 int main()
     2 {
     3     const int a  = 2;
     4     int* p = (int*)(&a);
     5     *p = 30;
     6     printf("%x
    ",&a);
     7     printf("%x
    ",p);
     8     printf("%i
    ",a);
     9     printf("%i
    ",*p);
    10     return 0;
    11 }
    复制代码

    结果:

    我们看到,在c里面,一个被const定义为常量的值,堂而皇之地被修改了,而且编译器没有报任何错误 !

    如果我们进一步深入可以发现,对于以上两个例子来说,a都是定义在某个函数之内的(比如main()函数),不管是c还是c++,本质上都只是将其当成一个普通的局部变量来对待,都只是在栈上分配空间。所以const根本就不能起到阻止修改其内存空间的作用,一个合法的强制类型转换就可以轻松搞定。c++比c好的地方就在于使用了constant folding的机制,使得常量的值跟对应的内存空间无关,从而保护了该常量值。

    以上的例子是针对局部的const常量而言

    对全局的const变量,c++仍旧采用constant folding策略,故以下代码是行得通的:

    //global variable
    const int a = 3;
    int arr[a];

    但是c会报错: error: variably modified 'arr' at file scope, 原因在于gcc认为a只是一个普通的全局变量,而变量是不能用来指定数组的长度的。当然,这是针对全局数组而言。

    如果是局部的数组的话,就算是int a = 3; int arr[a];这种都是可以的,因为c里面还有一种叫变长数组的东西(我晕~,貌似因为两者的实现机制不一样,这个要再看看)

    另外,对于全局a,在c和c++中如果我们仍然用int *p = (int*)(&a);这种方法来修改它内存中的值,编译时不会报错,但是运行时会报段错误,因为a是放在只读的全局数据区中,修改该区中的数据会引发段错误

    在vs编译器下:

    1.不支持变长数组,一个变量除非被声明为const,否则不能用来声明数组的长度。

    2.const变量,不管是全局的还是局部,都是放在只读数据区,所以无法用前面的方法来修改内存空间里面的值,编译时就会报错。

  • 相关阅读:
    phalcon之视图缓存
    Java NIO框架Netty教程(一) – Hello Netty
    setsockopt的作用
    支持向量机通俗导论(理解SVM的三层境地)
    quartz中的corn表达式(转)
    Applet 数字签名技术全然攻略
    SJTU 3001. 二哥的幸运
    OGRE之跳出漫长的编译等待
    VB.NET 数组的定义 动态使用 多维数组
    【Python】用Python的“结巴”模块进行分词
  • 原文地址:https://www.cnblogs.com/fnlingnzb-learner/p/9282962.html
Copyright © 2020-2023  润新知