const 、#define、constexpr
#define
define是C语言中的宏,拿来进行文本替换。如,
缺点:这个是在预处理阶段就完成的文本替换,与编译阶段是不同阶段,不会进行类型检查。#define number 100
,在程序的预处理阶段,会将程序中,所有出现number的地方,使用100来进行替换。- const
i. 编译时的值替代 --- const限定的变量,在编译阶段,编译器会进行常量折叠的一些优化操作。所谓常量折叠,就是化简常量表达式,即当遇到const限定的变量时,会用相应的值进行替换,使其变为一个立即数。当然,不是所有情况都能进行常量折叠,如对常量进行取地址操作。
eg:
运行结果:int main(){ const int a = 2; int *ptr = const_cast<int *>(&a);//改变常量属性 *ptr = 5; printf("a = %d\n" ,a);//此处进行常量折叠 printf("&a = %x\n", &a); printf("*ptr = %d\n",*ptr); printf("ptr = %x\n",ptr); printf("a = %d\n" ,a);////此处进行常量折叠 printf("&a = %x\n", &a); return 0; }
分析:
按&a,ptr,&a顺序输出的地址都不变,即说明处理的一直都是常量区的那块内存。当强行改变常量属性,对内存进行写操作时,再次输出常量 a 的值,还是原来的 2 ,而不是 3 ,此处说明,这里已经是被编译器优化了,编译期进行了值替代。ii. 运行时常量 -- 如果能确定一个变量,在其生存期之间,一直保持值不变,也可以用const来限定。
eg:
运行结果:int main(){ const int a = cin.get();//get()取单个字符 cout <<a; return 0; }
分析:
说明可以是运行时的const变量iii. const可以用来限定集合,如数组。编译器在编译阶段,不能把集合放在它的符号表中,而是必须分配内存,表明“不能改变的一块存储”。在编译时期,集合中的值,是不可使用的。
eg:
Tips:int main(){ const int array[3]={0,1,2}; float temp[array[0]];//此种行为编译器会报错 //因为array数组中的值在编译时不能使用,是运行时的存储值 }
C++中const与C中的const的区别:
const默认内部连接,作用域仅在本文件,而C中,默认外部连接。 - constexpr
constexpr是C++11提出的,目的是让编译器在编译时期判断表达式是否是常量表达式,若是,则可以在编译时就进行一些优化工作,提高效率。如常量折叠等;若不是,即报错。 i. constexpr修饰变量
constexpr int a = 1;//相当于const限定的编译时可确定值的用法 constexpr int b = cin.get();//编译器报错,此为运行时确定的存储
ii. constexpr修饰函数
当constexpr修饰的函数返回值用作常量表达式时,如用作数组声明中的维度,要求该函数中,定义的所有变量均为编译时可决定的值,且不能进行取地址等复杂操作,并且要求传入的参数也必须是常量表达式。
若返回结果不用做常量表达式,即权当普通函数使用。
eg:返回值作为常量表达式使用:程序可编译执行 constexpr int test(int a) { int b = 2;//个人猜测当返回值用作常量表达式时,b会当做constexpr变量使用 //printf("b = %d, &b = %x\n", b, &b);//若注释去掉,编译器报错,constexpr函数无法生成常数表达式 return b; } int main() { int a = 1; int b = 1; //int array[test(a+b)]; //若注释去掉,编译器报错,变量a的值不可用作常量 int array[test(1)]; return 0; }
返回值不做常量表达式使用: 传参不做要求(在以上程序加test(a+b);进行测试,通过) 返回值是否为常数表达式不做要求
- 一个constexpr修饰的指针的初始值必须是nullptr或者0,或者是存储于某个固定地址中的对象(如函数体外定义的变量或函数体内的static变量),且constexpr修饰的是指针,而不是指针指向的对象。(即xxx *const ptr;)