10. const 关键字

const 关键字 是 C 语言中的一个类型说明符(也叫类型限定符),它限制一个变量在操作的时候只能以只读的方式进行操作,不允许修改。

const 的中文含义是 常量常数 的意思,但并不是说被 const 修饰的变量是常量,因为常量通常是不可变的字面值,而被 const 修饰的变量我们通常称之为 常变量只读变量,而不是常量

在 C 语言中,对常变量的修改编译器会报错。

常变量声明的语法:

const 变量类型 变量名1 = 初始值1, 变量名2 = 初始值2, ...
// 或
变量类型 const 变量名1 = 初始值1, 变量名2 = 初始值2, ...

说明:

  1. const 关键字可以放在 变量类型 的前面或后面,效果是一样的。
  2. 常变量在声明时必须进行初始化,否则编译器会报错。
  3. const 关键字是编译器层面的类型限定符。这个类型限定符可以通过强制类型转换为非常变量的指针进行修改,但不建议这样做。

示例

// filename: const_variable.c
#include <stdio.h>

int main(int argc, char *argv[]) {
    const double pi = 3.141592653589793, e = 2.718281828459045;
    int const max_size = 1024;

    printf("pi:%f, e:%f\n", pi, e);
    printf("max_size:%d\n", max_size);

    pi = 3.14; // 对常变量的修改会报错

    return 0;
}

编译报错如下:

weimingze@mzstudio:~$ gcc const_variablea.c
a.c: In function ‘main’:
a.c:10:8: error: assignment of read-only variable ‘pi’
   10 |     pi = 3.14; // 对常变量的修改会报错
      |        ^

const 关键字的作用:

  1. 提高程序的健壮性,从编译器层面进行类型检查,防止变量被无意修改,减少运行时错误。
  2. 提高代码可读性,开发人员看到 const 修饰的变量就知道这个变量是不应该被改变的。
  3. 有助于编译器优化,编译器知道某些变量的值不会改变,可能会进行一些优化。

下面我们来学习 const 说明符在指针上的应用。

当我们声明一个指针时,比如:char *pch; 其实说明了两种数据类型:

  1. pch 是指针变量,类型是 char*
  2. pch 指针指向的数据类型为 char 类型,即 *pch 解引用后是一个 char 类型的数据。

当我们要用 const 修饰指针时,我们要想好是指针的指向不变,还是指针指向的数据内容不变,还是指针指向和指向的内容都不变,这几种写法在语法层面是不一样的。下面我们来举例说明。

1、指针和指向的数据都可变

char ch1 = 'A';
char ch2 = 'B';
char *pch1 = &ch1;

上述写法中 pch1 = &ch2;是合法的, *pch1 = 'C'; 也是合法的。即指针和指针指向的数据都可变。

2、指针指向的数据不可变

char ch1 = 'A';
char ch2 = 'B';
const char *pch1 = &ch1;
char const *pch2 = &ch2;

上述写法中 pch1 = &ch2;是合法的, *pch1 = 'C'; 是不合法的。即指针可变,指针指向的数据不可变。

3、指针不可变

char ch1 = 'A';
char ch2 = 'B';
char * const pch1 = &ch1;

上述写法中 pch1 = &ch2;是不合法的, 但 *pch1 = 'C'; 是合法的。即指针不可变,指针指向的数据可变。

4、指针和指针指向的数据都不可变

char ch1 = 'A';
char ch2 = 'B';
const char * const pch1 = &ch1;
char const * const pch2 = &ch2;

上述写法中 pch1 = &ch2;是不合法的, *pch1 = 'C'; 也是不合法的。即指针不可变,指针指向的数据也不可变。

另外还需要说写一下 const 说明符的一个细节,就是可以为指针添加 const 说明符是允许的。但要去掉 const 说明符则需要显式调用强制类型转换。否则将在编译时报警告或错误。如下面的示例中。可以将没有 const 说明符的指针赋值给有 const 说明符的指针,但反之则会报告警告。

示例:

// filename: const_alarm.c
#include <stdio.h>

int main(int argc, char *argv[]) {
    char ch1 = 'A';
    char * pch1 = &ch1;
    const char * pch2;
    char * pch3;

    pch2 = pch1; // 没有 const 修饰符的指针可以赋值给有const修饰符的指针。
    pch3 = pch2; // 此处编译报告警告

    printf("%c, %c, %c\n", *pch1, *pch2, *pch3);
    return 0;
}

编译运行结果如下:

weimingze@mzstudio:~$ gcc -o const_alarm const_alarm.c
const_alarm.c: In function ‘main’:
const_alarm.c:10:10: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
   10 |     pch3 = pch2; // 此处编译报告警告
      |          ^
weimingze@mzstudio:~$ ./const_alarm
A, A, A

实验:

按上述讲述内容写程序验证 const 修饰指针是的各种情况是否正确。