天天看点

才搞清楚常量的存储位置

 一个形如42的值被称为字面值常量。字面值常量的形式和值决定了常量的类型。例如0x42是16进制表示的整型常量。‘a'是char型字面值。字面值常量顾名思义由字面意思表示,是常量。字面值常量在程序中是直接表示的,整型直接写出大小,字符直接写出字符。一个字面值常量在编译时被直接解析为立即数,编译器内部维护字面值常量的类型。

      常量表达式是指在编译过程中,该表达式的值不会改变,且编译过程中可以立即得到结果的表达式。一部分const对象是常量表达式,由常量表达式初始化的const对象也是常量表达式。常量表达式在程序运行时不会改变,即使一个程序多次启动或外部参数发生变化,该值也不会改变。编译器在编译时可能把常量表达式直接替换为立即数,具体要看编译环境。一般来讲,字面值常量属于常量表达式。

      C++中允许将变量声明为constexpr类型以使编译器在编译时检查该变量是否是常量表达式。声明为constexpr的变量一定是常量表达式。且初始化必须用常量表达式。

例如:

   const int a = 12;    a是常量表达式

   const int b = a+1;  b也是常量表达式

   const int c = getsize();   c不是常量表达式,编译器编译时无法确知getsize()的执行结果。

   constexpr int c = getsize();  将会报错

      字面值类型是指编译时就能得到结果的类型,具体包括算术类型、引用和指针。自定义类、IO类不属于该类型。字面值类型的对象有严格的要求,字面值类型是那些具有常量表达式属性的对象的类型。例如:字面值常量是算术类型。对于引用和指针,其限定比较严格。不是所有的指针都是常量表达式。只有那些在编译时就确定地址指向的指针才是常量表达式,引用同理。因此nullptr、NULL、指向固定地址的指针是字面值类型。那么,如何判断指针是否指向固定地址呢?

      程序在内存中的组织形式是段,有堆栈段、数据段和代码段。对于数据指针指向数据,函数指针则指向某个代码。

才搞清楚常量的存储位置

数据段包括全局/静态存储区,常量存储区。对于全局变量,其指针是constexpr的;此类变量要占用数据段(全局存储区),而程序运行时,代码段和数据段大小位置均不会改变,因此编译器可以确定地址指向,是constexpr的。此外,函数内部定义的static静态变量,也会在数据区(静态存储区)使用固定地址,因此指针也是constexpr的。对于定义在函数内部的变量,由于要在栈中开辟内存空间,而栈的情况要看程序运行状态,因此这类变量没有确定的地址,其指针不是constexpr的。代码段不会改变,函数指针也是constexpr的。

2016/09/24--------------------------------------------------------------------------------------------------

对常量的理解还是有误区,以const int i=10;为例,之前一直误认为i是存储在常量存储区里的,大错特错!因为无法解释const栈变量的存储位置。实际上并不存在常量存储区,只有全局/静态存储区。const类型的存储跟一般的变量没有区别,在外部定义的存储在全局数据区,static的存储在静态数据区,在函数内部定义的存储在栈,const跟非const存储上没区别,只不过是read only的。

参考 http://bbs.csdn.net/topics/340089467