#define、const、constexpr

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;
    }
    运行结果:
    class
    分析:
    按&a,ptr,&a顺序输出的地址都不变,即说明处理的一直都是常量区的那块内存。当强行改变常量属性,对内存进行写操作时,再次输出常量 a 的值,还是原来的 2 ,而不是 3 ,此处说明,这里已经是被编译器优化了,编译期进行了值替代。

    ii. 运行时常量 -- 如果能确定一个变量,在其生存期之间,一直保持值不变,也可以用const来限定。
    eg:

    int main(){
      const int a = cin.get();//get()取单个字符
      cout <<a;
    
      return 0;
    }
    运行结果:
    class
    分析:
    说明可以是运行时的const变量

    iii. const可以用来限定集合,如数组。编译器在编译阶段,不能把集合放在它的符号表中,而是必须分配内存,表明“不能改变的一块存储”。在编译时期,集合中的值,是不可使用的。
    eg:

    int main(){
      const int array[3]={0,1,2};
      float temp[array[0]];//此种行为编译器会报错
      //因为array数组中的值在编译时不能使用,是运行时的存储值
    }
    Tips:
    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;)

猜你喜欢

转载自www.cnblogs.com/LeeQMoon/p/12405770.html
今日推荐