常量折叠说的是,在编译阶段,对该变量进行值替换,同时,该常量拥有自己的内存空间,并非像宏定义一样不分配空间。
示例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++常量折叠
网友评论