常量折叠

 

可折叠的常量像宏一样,在预编译阶段对常量的引用一律被替换为常量所对应的值,就和普通的宏替换没什么区别。

#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并不会消失,编译器会把他放入到符号表中,同时,会为该变量分配空间,栈空间或者全局空间。

int main()
{
    int i0 = 11;
 
    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

至少能说明两点:
1、ij地址相同,指向同一块空间,i虽然是可折叠常量,但是,i确实有自己的空间

2、ij指向同一块内存,但是*j = 1对内存进行修改后,按道理来说,*j==1,i也应该等于1,而实验结果确实i实实在在的等于0,这是为什么呢,就是本文所说的内容,i是可折叠常量,在编译阶段对i的引用已经别替换为i的值了,也就是说

printf("%d\n%d\n%d\n%d\n",&i,j,i,*j)

中的i已经被替换,其实已经被改为

printf("%d\n%d\n%d\n%d\n",&i,j,0,*j)

 

对可折叠的常量的引用会被替换为该常量的值,而对变量的引用就需要访问变量的内存。

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

以上来自原文链接:https://blog.csdn.net/yby4769250/article/details/7359278

 

 

有关C++语言的const常量的考察点:肯定是const常量的内存不是分配在read-only的存储区的,const常量的内存分配区是很普通的栈或者全局区域。也就是说const常量只是编译器在编译的时候做检查,根本不存在什么read-only的区域。

所以说C++的const常量和常量字符串是不同的,常量字符串是存储在read-only的区域的,他们的具体的存储区域是不同的。
常量折叠就是将常量表达式计算求值,并用求得的值来替换表达式,放入常量表。可以算作一种编译优化。(预编译阶段)

gcc编译的C语言的const常量,这里并没有做常量折叠的这种优化,类似于const常量前面加上volatile这个关键字。

 

posted @ 2022-08-13 00:21  Ben002  阅读(189)  评论(0编辑  收藏  举报