常量折叠

作者: saviochen | 来源:发表于2017-08-03 23:19 被阅读64次

常量折叠说的是,在编译阶段,对该变量进行值替换,同时,该常量拥有自己的内存空间,并非像宏定义一样不分配空间。

示例1
#define PI 3.14  
int main()  
{  
    const int r = 10;  
    int p = pI; //预编译阶段产生宏替换,PI直接替换为3.14,即int p = 3.14;  
    int len = 2*r; //常量折叠,对常量r的引用会替换成其对应的值,相当于int len = 2*10;  
    return 0;  
}

如上述代码中所述,常量折叠表面上的效果和宏替换是一样的,只是,“效果上是一样的”,而两者真正的区别在于,宏是字符常量,在预编译完宏替换完成后,该宏名字会消失,所有对宏如PI的引用已经全部被替换为它所对应的值,编译器当然没有必要再维护这个符号。

而常量折叠发生的情况是,对常量的引用全部替换为该常量如r的值,但是,常量名r并不会消失,编译器会把他放入到符号表中,同时,会为该变量分配空间,栈空间或者全局空间。

示例2

为了能更清楚的体现出常量折叠,下面做几个对照实验,看代码和输出便了然:

int main()  
{  
    const int i = 0;         //定义常量i  
    int *j = (int *) &i;   //看到这里能对i进行取值,判断i必然后自己的内存空间  
    *j = 1;                  //对j指向的内存进行修改  
    printf("%d\n%d\n%d\n%d\n", &i, j, i, *j); //观看实验效果  
    const int ck = 9;     //这个对照实验是为了观察,对常量ck的引用时,会产生的效果  
    int ik = ck;  
  
    int i1 = 5;           //这个对照实验是为了区别,对常量和变量的引用有什么区别  
    int i2 = i1;  
 
    return 0;  
}  

以上代码输出为:

0012ff7c
0012ff7c
0
1

说明了两点:

  • i,j地址相同,指向同一块空间,i虽然是可折叠常量,但是,i确实有自己的空间

  • i,j指向同一块内存,但是*j = 1对内存进行修改后,按道理来说,*j==1, i也应该等于1,而实验结果i却等于0。这是为什么呢,就是本文所说的内容,i是可折叠常量,在编译阶段对i的引用已经别替换为i的值了,即:
    printf("%d\n%d\n%d\n%d\n", &i, j, i, *j);
    其实已经被改为
    printf("%d\n%d\n%d\n%d\n", &i, j, 0,*j)

汇编代码验证

将示例2转为汇编代码,进行验证

4:    int main()  
5:    {  
00401030   push        ebp  
00401031   mov         ebp,esp  
00401033   sub         esp,5Ch  
00401036   push        ebx  
00401037   push        esi  
00401038   push        edi  
00401039   lea         edi,[ebp-5Ch]  
0040103C   mov         ecx,17h  
00401041   mov         eax,0CCCCCCCCh  
00401046   rep stos    dword ptr [edi]  
6:        int i0 = 11;  
00401048   mov         dword ptr [ebp-4],0Bh  
7:  
8:        const int i=0;  
0040104F   mov         dword ptr [ebp-8],0 //编译器确实为常量i分配了栈空间,并赋值为0  
9:        int *j = (int *) &i;  
00401056   lea         eax,[ebp-8]  
00401059   mov         dword ptr [ebp-0Ch],eax  
10:       *j=1;  
0040105C   mov         ecx,dword ptr [ebp-0Ch]  
0040105F   mov         dword ptr [ecx],1  
11:                                            //对常量的引用和变量的引用的区别观察  
12:       const int ck = 9;  
00401065   mov         dword ptr [ebp-10h],9   //为常量分配栈空间   
13:       int ik = ck;  
0040106C   mov         dword ptr [ebp-14h],9   //对常量ck的引用,会直接替换为常量的值9
14:  
15:       int i1 = 5;  
00401073   mov         dword ptr [ebp-18h],5  
16:       int i2 = i1;                        //这里引用变量i1,对i2进行赋值,是先去
//栈中先取出i1的值,到edx寄存器中,然后再把值mov到i2所在的内存中
0040107A   mov         edx,dword ptr [ebp-18h]  
0040107D   mov         dword ptr [ebp-1Ch],edx  
17:  
18:  
19:       return 0;  
00401080   xor         eax,eax  
20:  
21:   }  

通过上述实验的分析可看出,常量的使用将被折叠,而对变量的使用就需要访问变量的内存。

转自C++常量折叠

相关文章

  • 常量折叠

    常量折叠说的是,在编译阶段,对该变量进行值替换,同时,该常量拥有自己的内存空间,并非像宏定义一样不分配空间。 示例...

  • Java之常量折叠、常量传播和Global Value Numb

    常量折叠 常量折叠是Java在编译期做的一个优化,简单的来说,在编译期就把一些表达式计算好,不需要在运行时进行计算...

  • 编译优化算法

    参考资料: 1 编译器常用优化方法 常量传播 将能够计算出结果的变量直接替换为常量 优化后 常量折叠 多个变量计算...

  • Python隐藏特性:字符串驻留、常量折叠

    下面是Python字符串的一些微妙的特性,绝对会让你大吃一惊。 案例一: 案例二: 案例三: 很好理解, 对吧? ...

  • Java(常量的使用与概述)

    常量分类:a>字面值常量 b>自定义常量 A>字面值常量·字符串常量·整数 常量·小数常量·字符常量·布尔常量 ...

  • iOS开发之C语言实用概述

    一、常量和变量:常量的定义:const int a = 10; 常量:整型常量实型常量字符型常量字符串常量 变量:...

  • Java基础语法之常量

    1.Java中常量分类 字面值常量 自定义常量 2.字面值常量的分类 字符串常量 整数常量 小数常量 字符常量 布...

  • java基础

    1. 常量 字符串常量 整数常量 小数常量 字符常量:单个数字,单个字母,单个符号 布尔常量 空常量 2. ...

  • Xcode 折叠快捷键

    局部折叠(折叠一个函数) 全局折叠(折叠当前文件下的全部函数) 折叠注释块

  • Xcode快捷键

    折叠代码块: 局部折叠(折叠一个函数)Command+Option+Left/Right 全局折叠(折叠全部函数)...

网友评论

    本文标题:常量折叠

    本文链接:https://www.haomeiwen.com/subject/tpumlxtx.html