const在C语言中究竟是什么意思?

99ANYc3cd6
预计阅读时长 15 分钟
位置: 首页 C语言 正文

一句话概括

const 是 C 语言中的一个类型限定符(Type Qualifier),它用来告诉编译器:“请把一个变量标记为只读的,它的值在初始化后就不能再被修改了。”

c语言const是什么意思
(图片来源网络,侵删)

const 就是用来创建常量的。


const 的核心作用与好处

使用 const 主要有以下三个核心好处:

  1. 提高代码安全性:它能防止代码中意外地修改不应该被修改的变量,减少程序运行时的 bug。
  2. 增加代码可读性:当其他程序员(或者未来的你)看到 const 时,就能立刻明白这个变量是一个常量,不应该被赋值,从而理解代码的意图。
  3. 帮助编译器优化:编译器知道一个 const 变量的值永远不会改变,因此它可以进行一些更激进的优化,有时甚至能生成更高效的机器码。

const 的基本用法

const 的语法规则有点灵活,但核心思想不变。const 关键字可以放在类型的前面或后面,效果是一样的,把 const 放在变量名前面是更现代、更推荐的风格。

修饰普通变量(最常见)

这是最简单的用法,创建一个只读的变量。

c语言const是什么意思
(图片来源网络,侵删)
// 推荐写法 (const 在变量名前)
const int MAX_AGE = 100;
// 也可以这样写 (const 在类型后,效果相同)
// int const MAX_AGE = 100;
// 下面的代码会编译错误!
// MAX_AGE = 101; // error: assignment of read-only variable 'MAX_AGE'

这里,MAX_AGE 被定义为一个常量,它的值是 100,任何试图修改 MAX_AGE 的操作都会被编译器报错。

修饰指针(这是最容易混淆的地方)

const 和指针 结合时,情况就变得复杂了。const 的位置决定了“什么”是不可变的。

我们分两种情况来看:

情况 A:const 修饰指针指向的数据(内容不可变)

语法:const int * p; 或者 int const * p;

c语言const是什么意思
(图片来源网络,侵删)

解读const 紧挨着 int,说明 int(也就是 p 指向的那个整数)是只读的,指针 p 本身是可以指向别的地方的。

int a = 10;
int b = 20;
const int * p = &a; // p 是一个指向 "只读整数" 的指针
// *p = 30; // 错误!不能通过 p 修改它指向的数据,因为数据是只读的
p = &b;     // 正确!可以改变 p 指向,让它指向 b

情况 B:const 修饰指针本身(指针地址不可变)

语法:int * const p;

解读const 紧挨着 ,说明指针 p 本身是只读的,你不能让 p 指向新的地址,但是你可以修改 p 指向的那个数据。

int a = 10;
int b = 20;
int * const p = &a; // p 是一个 "只读指针",它必须一直指向 a
*p = 30;     // 正确!可以修改 p 指向的数据 a 的值
// p = &b;   // 错误!不能改变 p 指向,p 是一个只读指针

情况 C:两者都不可变(最严格的指针)

语法:const int * const p;

解读:一个 const 修饰数据,另一个 const 修饰指针,这意味着指针本身它指向的数据都是只读的。

int a = 10;
const int * const p = &a;
// *p = 30; // 错误!数据不可变
// p = &b;   // 错误!指针本身也不可变

修饰函数参数

将函数参数声明为 const 是一个非常好的编程习惯,它向调用者承诺:“我不会在这个函数内部修改这个参数的值。”

// 一个打印数组的函数,承诺不会修改数组内容
void print_array(const int arr[], int size) {
    for (int i = 0; i < size; i++) {
        // arr[i] = 0; // 错误!不能修改 const 数组
        printf("%d ", arr[i]);
    }
    printf("\n");
}
int main() {
    int my_numbers[] = {1, 2, 3, 4, 5};
    print_array(my_numbers, 5);
    return 0;
}

修饰函数返回值

当函数返回一个指针时,如果返回的数据不应该被调用者修改,就可以用 const 来修饰返回类型。

const int * get_max_value() {
    static int max_value = 1000; // 使用 static 确保函数返回后变量还存在
    return &max_value;
}
int main() {
    const int * p_max = get_max_value();
    printf("Max value is: %d\n", *p_max);
    // *p_max = 2000; // 错误!不能通过返回的指针修改数据
    return 0;
}

const#define 的区别

很多初学者会混淆 const 和 C 语言的宏定义 #define,它们虽然都能创建常量,但有本质区别:

特性 const #define
类型 有类型,编译器知道它的类型,可以进行类型检查。 无类型,只是简单的文本替换,编译器不知道它的类型。
作用域 有作用域,遵循 C 语言的变量作用域规则(只在 内有效)。 无作用域,从定义到文件结尾都有效,除非用 #undef
处理时机 编译时,编译器会处理它,会进行类型检查和内存分配(。 预处理时,在编译之前,预处理器会直接进行文本替换。
调试 可以调试,在调试时能看到 const 变量的名字和值。 无法调试,预处理器替换后,名字就消失了,调试时只能看到替换后的值。
定义方式 定义变量,可以指定类型。 定义宏,不指定类型。

在 C 语言中,优先使用 const,除非你需要做一些 const 做不到的事情(比如定义宏函数,或者定义一个全局的、无类型的常量)。


一个特殊的陷阱:const 全局变量的“内部链接”

这是一个在 C 语言中非常重要的知识点。

在 C 语言中,一个全局 const 变量(没有 static默认具有内部链接,这意味着它只在定义它的那个源文件(.c 文件)中可见。

这与普通的全局变量(默认外部链接)形成鲜明对比。

示例:

const_var.c

#include <stdio.h>
// 这是一个全局常量,具有内部链接
const int GLOBAL_CONST = 100;

main.c

#include <stdio.h>
// 尝试从另一个文件访问
extern int GLOBAL_CONST; // extern 声明
int main() {
    printf("Global const value: %d\n", GLOBAL_CONST); // 编译错误!链接器找不到 GLOBAL_CONST
    return 0;
}

编译这段代码时,main.c 中的 extern 声明会告诉编译器:“GLOBAL_CONST 这个变量应该在其他地方定义”,由于 const_var.c 中的 GLOBAL_CONST 具有内部链接,main.c 的链接器根本“看不见”它,从而导致链接错误。

如何解决? 如果你想让一个全局 const 变量像普通全局变量一样被其他文件访问,你需要显式地使用 extern 关键字。

const_var.c (修改后)

#include <stdio.h>
// 显式声明为外部链接
extern const int GLOBAL_CONST;
const int GLOBAL_CONST = 100;

或者,在声明时加上 extern

// 在头文件中声明
extern const int GLOBAL_CONST;
// 在 .c 文件中定义
const int GLOBAL_CONST = 100;

这样,GLOBAL_CONST 就可以被其他文件通过 extern 正确访问了。

注意:在 C++ 中,这个规则被改变了,C++ 中的全局 const 变量默认具有外部链接,行为和普通全局变量一致,这也是 C 和 C++ 在兼容性上的一个常见陷阱。


  • const 是创建只读变量(常量)的关键字。
  • 核心好处是安全、可读、可优化
  • const 修饰指针时,位置决定了“什么”不可变:const int * p不可变),int * const p(指针本身不可变)。
  • 优先使用 const 而不是 #define
  • C 语言中,全局 const 变量默认是内部链接,不能被其他文件直接访问,这一点需要特别注意。
-- 展开阅读全文 --
头像
c语言 是男人就下100层
« 上一篇 前天
为何织梦页面直接显示原代码?
下一篇 » 前天

相关文章

取消
微信二维码
支付宝二维码

目录[+]