const
在 C 和 C++ 中,const 有显著的区别。主要差异如下:
1. 默认作用域链接性
C:
const全局变量默认具有外部链接(external linkage)c// file1.c const int MAX = 100; // 外部链接,其他文件可见 // file2.c extern const int MAX; // 正确,可以访问C++:
const全局变量默认具有内部链接(internal linkage)cpp// file1.cpp const int MAX = 100; // 内部链接,仅在当前文件可见 // file2.cpp extern const int MAX; // 链接错误!找不到定义在 C++ 中需要显式使用
extern:cpp// file1.cpp extern const int MAX = 100; // 外部链接 // file2.cpp extern const int MAX; // 正确
2. 常量表达式处理
C:
const变量不是编译时常量表达式cconst int size = 10; int arr[size]; // C99 之前错误,size 不是常量表达式C++:
const变量是编译时常量表达式(如果初始化值是常量)cppconst int size = 10; int arr[size]; // 正确,size 是常量表达式在 C++11 之后,使用
constexpr更明确。
3. 与指针的关系
虽然语法相似,但类型系统更严格:
cpp
// C++
const int* p1; // 指向常量的指针
int const* p2; // 同上
int* const p3; // 常量指针
const int* const p4; // 指向常量的常量指针
// C 语法相同,但 C++ 类型检查更严格
void foo(const int* p) {
int* q = p; // C++ 错误,C 警告(需要强制转换)
}4. 在函数中的应用
C++ 特有的用法:
常量成员函数:
cpp
class MyClass {
int value;
public:
int get() const { // 承诺不修改对象
return value;
}
};
const MyClass obj;
obj.get(); // 正确,调用常量成员函数常量引用参数:
cpp
void func(const std::string& str); // 避免复制,承诺不修改5. 初始化要求
C:
const变量可以不初始化(但默认值不确定)cconst int x; // C 允许,值未定义C++:
const变量必须初始化cppconst int x; // C++ 错误:未初始化的常量 const int y = 5; // 正确
6. 字符串字面量
c
// C
const char* str = "hello";
str[0] = 'H'; // 运行时错误(未定义行为)
// C++
const char* str = "hello"; // 字符串字面量是 const char[]
char* str2 = "hello"; // C++ 错误,需要强制转换7. 与宏定义的比较
c
// C 中常用宏定义常量
#define MAX_SIZE 100
// C++ 推荐使用 const
const int MAX_SIZE = 100;
constexpr int MAX_SIZE2 = 100; // C++118. 类型转换规则
C:允许从
const T*隐式转换为T*(会有警告)cconst int* p1; int* p2 = p1; // 警告,但允许C++:不允许隐式转换,需要显式
const_castcppconst int* p1; int* p2 = p1; // 错误 int* p3 = const_cast<int*>(p1); // 显式转换
总结对比表
| 特性 | C | C++ |
|---|---|---|
| 默认链接性 | 外部链接 | 内部链接 |
| 常量表达式 | 不是(C99前) | 是 |
| 函数中的使用 | 有限 | 常量成员函数、引用参数 |
| 初始化要求 | 可选 | 必须 |
| 类型安全性 | 较宽松 | 严格 |
| 字符串字面量 | char* | const char* |
| 数组大小 | 不能用于静态数组(C99前) | 可以 |
建议
- C 中使用
const主要表示"只读",不是真正的编译时常量 - C++ 中
const是类型系统的一部分,提供更强的保证 - C++11 后,对于编译时常量,优先使用
constexpr - 在多文件项目中,注意
const的链接性差异
理解这些差异有助于编写更安全、可移植的代码。