c和c++中const常见问题

本文详细比较了C++中的const和#define的区别,包括生命周期、作用域、可重定义性,以及const与指针和volatile的结合使用。同时介绍了const在左值引用、成员函数中的应用和嵌入式开发中的考虑因素。
摘要由CSDN通过智能技术生成

const 和 #define 的区别 ?

const 和指针一块出现的时候,到底谁不能修改 ?

const 和 volatile 能同时修饰一个变量吗 ?

const 在 c++ 中的作用 ?

1 const 和 #define 的区别

const 和 #define 的相同点:

(1) 常数

const 和 #define 定义的对象,我们都可以当做一个常数来使用。

const 和 #define 的区别:

(1) 生命周期

#define 在编译预处理的时候会做字符串替换,替换之后宏就不存在了,也就是说宏的生命周期只存在于源码和预处理阶段。在目标文件中,程序运行的时候,宏是不存在的。

const 修饰的变量,在编译阶段会做语法检查,如果有显式修改,会报编译错误。const 常量在运行时也是实际存在的,存在于栈或者数据段中。

(2) 作用域

#define 定义的宏,只要包含了这个头文件,都可以使用这个宏;在源文件中,宏定义之后的代码也都可以访问这个宏;即使宏定义函数内部,那么这个宏定义后边的其它函数也是可以使用这个宏的。

const 修饰的局部变量只能在函数内访问,const 修饰的全局变量和普通全局变量的作用域是相同的。

(3) #define 修饰的宏可以 redefine

如下代码,在函数 test2() 内部对HOURS_PER_DAY 进行了重定义。重定义虽然是在函数内部,但是对后边的函数都是生效的。在 test2() 中重定义,在函数 test3() 中也是生效的。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define HOURS_PER_DAY 24

void test1() {
  printf("1, hours per day = %d\n", HOURS_PER_DAY);
}

void test2() {
  #undef HOURS_PER_DAT
  #define HOURS_PER_DAY 20

  printf("2, hours per day = %d\n", HOURS_PER_DAY);
}

void test3() {
  printf("3, hours per day = %d\n", HOURS_PER_DAY);
}

int main() {
  test1();
  test2();
  test3();
  return 0;
}

在 c++ 编码规范中,推荐使用 const 常量,而不是 #define。

从上边的分析也可以看出来,#define 是可以重定义的,并且 #define 定义的宏没有作用域限制。这就可能给代码带来不安全性。

而对于 const 来说,局部变量的作用域只是函数内;全局 const 变量也不能重新修改。 const  的作用域限制更加严格,所以使用 const 安全性会更高。

2 const 和指针一块出现的时候,到底谁不能修改

const 修饰的是谁,那么谁就不能修改。

int a = 10;

int * const pa1 = &a; // const 修饰的是 int * 类型,是指针,所以 pa1 不能修改,*pa1 可以修改

const int *pa2 = &a; // const 修饰的是 int 类型,所以 pa2 可以修改,*pa2 不能修改

const int * const pa3 = &a; // pa3 和 *pa3 均不能修改

如下是代码和编译结果。

a 是 const 常量,所以不能修改。

p1 中 const 修饰的是 int 常量,所以 *p1 不能修改,p1 可以修改。

p2 中 const 修饰的是指针,所以 p2 不能修改,*p2 可以修改。

p3 const 修饰了指针和 int 值,所以 p3 不能修改,*p3 也不能修改。

3 const 和 volatile 能不能修饰同一个变量

可以。

这两个关键字,从字面意思上是有一些矛盾的。const 是说这个变量是常数,不能修改;volatile 又说这个变量是易变的。

但是两者可以修饰同一个变量,侧重点并不矛盾。const 是提醒编译器,这个变量是常数,不能在代码中显式修改,我们使用它的目的就是这样的,不让在代码中显式修改;volatile 说变量是易变的,告诉编译器,不要做访问优化,每次访问的时候都要到内存中去取值。

在嵌入式开发中,常常用到 volatile 来修饰寄存器变量,寄存器变量不允许软件显式修改,但是硬件可以修改。这个时候就可以使用 const 和 volatile 进行修饰。

4 const 在 c++ 中的作用

4.1左值引用指向右值

如下代码 ra2 是左值引用,左值引用不能直接指向一个右值。

ra3 是一个 const 左值引用,可以指向一个右值。

从运行结果可以看出来,const 左值引用可以指向右值,右值也是保存在栈里的, ra3 的地址和 a 的地址挨着。

从运行结果可以看出来,const 引用 ra3,通过地址间接修改也是可以修改的。

#include <iostream>
#include <string>


int main() {
  int a = 10;
  int &ra1 = a;
  // int &ra2 = 10; // error: cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’
  const int &ra3 = 10;
  std::cout << "a addr = " << &a << ", ra3 addr = " << &ra3 <<std::endl;

  int *p = (int *)&ra3;
  std::cout << "ra3 = " << ra3 << std::endl;
  *p = 100;
  std::cout << "ra3 = " <<ra3 << std::endl;
  return 0;
}

函数形参很多时候都声明为 const 左值引用,这样的话,传左值和右值都是可以的。

4.2修饰成员函数

用 const 修饰的成员函数,在函数中不能修改类的成员变量。

#include <iostream>
#include <string>

class Test {
public:
  Test() {
    a = 10;
    std::cout << "Test()" << std::endl;
  }

  ~Test() {
    std::cout << "~Test()" << std::endl;
  }

  void Do() const {
    a = 100;
  }

  void Do1(int data) {
    a = 100;
    data = 200;
  }

  int a;
};

int main() {
  Test t;
  t.Do();
  return 0;
}

5 参考

linux 下 c 语言中的局部 const 常量可以修改

 [c 语言] 实例观察 c 语言中 volatile 的作用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值