[c/c++] const

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 修饰的宏可以 redifine

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

cpp 复制代码
#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++ 中的作用

(1) 左值引用指向右值

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

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

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

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

cpp 复制代码
#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;
}

(2) 修饰成员函数

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

cpp 复制代码
#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 的作用

相关推荐
byxdaz8 小时前
C++内存序
c++
iuu_star8 小时前
C语言数据结构-顺序查找、折半查找
c语言·数据结构·算法
优雅的潮叭8 小时前
c++ 学习笔记之 malloc
c++·笔记·学习
苦藤新鸡10 小时前
8.最长的无重复字符的子串
c++·力扣
JoyCheung-11 小时前
Free底层是怎么释放内存的
linux·c语言
꧁Q༒ོγ꧂11 小时前
C++ 入门完全指南(四)--函数与模块化编程
开发语言·c++
汉克老师11 小时前
GESP2025年12月认证C++八级真题与解析(判断题8-10)
c++·快速排序··lcs·gesp八级·gesp8级
qq_4335545411 小时前
C++ manacher(求解回文串问题)
开发语言·c++·算法
HL_风神12 小时前
设计原则之迪米特
c++·学习·设计模式