• (转载)C++常量折叠和C语言中const常量对比


    (转载)http://www.360doc.com/content/12/0824/20/8093902_232153101.shtml
    #include <iostream>
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
      const int a = 10;
      int *p = (int *) &a;//让p指向与a相同的内存空间
      cout << *p << " " << a << endl;
      cout << p << " " << &p << endl;
      *p = 20;// 照里说a的值也应该改变,实际却没有,这就是常量折叠.
    
      cout << *p << " " << a << endl;
      cout << p << " " << &p << endl;
    
    
        // 这个"常量折叠"就是在编译器进行语法分析的时候,将常量表达式计算求值,
    
       // 并用求得的值来替换表达式,放入常量表。可以算作一种编译优化。
    
       // 我只是改了这个地址内容,但是a还是,
    
        // 因为编译器在优化的过程中,会把碰见的const全部以内容替换掉
    
       // (跟宏似的: #define PI 3.1415,用到PI时就用.1415代替),
    
       // 这个出现在预编译阶段;但是在运行阶段,它的内存里存的东西确实改变了!(下面演示)
    
      return 0;
    }


    输出结果:
    10 10

    0xbfda9ccc 0xbfda9cc8
    20 10
    0xbfda9ccc 0xbfda9cc8

    为了验证在运行阶段,a所在地址的内容确实被*p = 20改变了,我们单步调试如下:

    Reading symbols from /home/beijibing/zixue/unp2/svshm/test...done.

    (gdb) b 9

    Breakpoint 1 at 0x80487e7: file test.c, line 9.

    (gdb) run

    Starting program: /home/beijibing/zixue/unp2/svshm/test 

    10 10

    0xbffff39c 0xbffff398 // 前两个cout输出后,我们知道了存a和p的堆栈地址。

    Breakpoint 1, main (argc=1, argv=0xbffff454) at test.c:9

    9  *p = 20;   //在这里设了断点,先暂停查看现在堆栈内容

    (gdb) x/2x 0xbffff398 //从低地址查看2个字的内容

    0xbffff398: 0xbffff39c 0x0000000a   //可以看出0xbffff398中存放的是a的地址0xbffff39c,而0xbffff39c中存放的是0xa(10进制为10)

    (gdb) n

    11  cout << *p << " " << a << endl;

    (gdb) x/2x 0xbffff398

    0xbffff398: 0xbffff39c 0x00000014     //单步执行后在查看,发现0xbffff39c中的值被改为0x14(20),正如上面所述

    (gdb) n

    20 10

    12  cout << p << " " << &p << endl;

    (gdb) n

    0xbffff39c 0xbffff398

    19  return 0;

    (gdb) 

     

     

    总结:编译器会为常量分配了地址,但是在使用常量的时候,常量会被一立即数替换(保护常量,防止被破坏性修改)

    在C++中对于基本类型的常量,编绎器并不为其分配存储空间,编译器会把它放到符号表,当取符号常量的地址等操作时,将强迫编译器为这些常量分配存储空间,编译器会重新在内存中创建一个它的拷贝,通过地址访问到的就是这个拷贝而非原始的符号常量。

     

    和C语言中const常量对比:

     

    #include <stdio.h>
    
    int main()
    {
      const int a = 10;
      int *p = (int *) &a;
      printf("%d, %d\n",*p,a) ;
      printf("%x, %x\n",p,&p) ;
    
      *p = 20;
     // a = 30;  //常量是不能修改的,error: assignment of read-only variable 'a’
    
      printf("%d, %d\n",*p,a) ;
       printf("%x, %x\n",p,&p) ;
    
      return 0;
    }

     

     

     

    编译运行结果:

    10, 10

    bfea80fc, bfea80f8

    20, 20

    bfea80fc, bfea80f8

    可以查看二进制文件,发现a并没有在链接的时候占用.rodata空间。

    注意:可以看出a被修改了,a是在栈上分配的常量,a本身不能修改,但是可以用指针p指向a,然后修改p指向的内容,这样就可以修改常量a的内容了。
  • 相关阅读:
    SolidEdge如何绘制阵列之后取消掉某一些
    SolidEdge如何绘制变化半径倒圆角
    SolidEdge如何复制特征 建立类似于UG 块的概念
    SolidEdge如何打开或关闭自动标注尺寸
    SolidEdge 装配体中如何快速的搞定一个面上所有螺丝 如何在装配体上进行阵列
    SolidEdge 如何由装配图快速生成爆炸视图
    SolidEdge 如何由装配图快速进行标注和零件序号编写 制作BOM表
    [Angular 8] Take away: Web Components with Angular Elements: Beyond the Basics
    [Angular 8] Take away: Tools for Fast Angular Applications
    [Algorithm] Calculate Pow(x,n) using recursion
  • 原文地址:https://www.cnblogs.com/Robotke1/p/3080377.html
Copyright © 2020-2023  润新知