字符常量是char类型单字节值,可参与运算;字符串字面量是const char[n]数组,含结尾'\0',不可修改且具静态存储期,二者类型与操作方式严格区分,混用导致编译错误或未定义行为。

字符常量和字符串字面量在类型、内存布局、可赋值对象、操作方式上完全不同,混用会导致编译错误或未定义行为。
字符常量是 char 类型,字符串字面量是 const char[N] 数组
字符常量如 'A' 是单个字符,编译器将其视为 char(或带符号/无符号整型,取决于平台),占 1 字节,可直接参与算术运算:'A' + 1 得到 'B'。字符串字面量如 "A" 是长度为 2 的数组:const char[2],内容为 {'A', '\0'},类型不是 char,也不能隐式转成 char。
常见错误现象:
-
char c = "A";—— 编译失败:不能把const char[2]初始化char -
char c = 'A';—— 正确 -
sizeof('A')通常是 1;sizeof("A")是 2
字符串字面量不可修改,且地址具有静态存储期
"hello" 存储在只读数据段(.rodata),任何试图修改它的行为都是未定义的,例如:
-
char* p = "hello"; p[0] = 'H';—— 运行时可能崩溃(SIGSEGV) -
const char* p = "hello";更安全,但不改变底层只读属性 -
char s[] = "hello";才真正复制到栈上,s[0] = 'H'合法
注意:"hello" 是左值,支持取地址:&"hello"[0] 合法;但不能赋值或自增,因为它是“不可修改的左值”。
函数参数传递时类型不兼容容易踩坑
C++ 标准库中很多函数明确要求 const char*(如 std::strlen、std::printf 的 %s),传入 char 会编译失败;反之,期望 char 的地方(如 std::toupper)传 "a" 也错。
-
std::toupper('a')—— 正确 -
std::toupper("a"[0])或std::toupper(*"a")—— 可行,但绕弯 -
std::strlen('a')—— 错误:无法将char转为const char* -
std::strlen("a")—— 正确,"a"隐式转为const char*
性能影响:字符串字面量是编译期确定的静态数据,零运行时开销;而 std::string 构造它会触发堆分配(除非用 string_view)。
字符串字面量拼接是编译期行为,字符常量不能拼接
C++ 允许相邻字符串字面量自动拼接:"ab" "cd" 等价于 "abcd",这是词法分析阶段完成的,不产生运行时开销。
auto s = "ab" "cd"; // s 类型是 const char[5]auto c = 'a' 'b'; // 编译错误:字符常量不能连写auto x = 'a' + 'b'; // 合法,但结果是 int(97+98=195),不是字符串
容易被忽略的一点:多字节字符(如 UTF-8 中文)写在字符串字面量里是合法的,但写成字符常量如 '你好' 是非法的——C++ 字符常量只允许单个 char、wchar_t、char16_t 或 char32_t,且必须是单字符字面量。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











