C 参考手册
- C 语言
- C 的历史
- 基本概念
- 表达式
- 声明
- 初始化
- 函数
- 语句
- 静态断言
- 字符常量
- 函数声明
- 函数定义
- 转义序列
- 翻译阶段
- 标识符
- 作用域
- 生存期
- 查找与命名空间
- ASCII 码表
- 类型
- 遵从性
- 算术类型
- restrict 类型限定符
- 类型
- 对象与对齐
- 主函数
- 未定义行为
- 内存模型
- if 语句
- switch 语句
- for 循环
- while 循环
- do-while 循环
- continue语句
- break 语句
- goto语句
- return 语句
- 值类别
- 求值顺序
- 整数常量
- 浮点常量
- 字符串字面量
- 复合字面量
- 常量表达式
- 隐式转换
- 成员访问运算符
- 逻辑运算符
- 比较运算符
- 算术运算符
- 赋值运算符
- 自增/自减运算符
- 其他运算符
- sizeof 运算符
- _Alignof 运算符
- 转型运算符
- C 运算符优先级
- 泛型选择
- 标量初始化
- 数组初始化
- 结构体与联合体初始化
- 指针声明
- 数组声明
- 枚举
- 存储类指定符
- const 类型限定符
- volatile 类型限定符
- 结构体声明
- 联合体声明
- 位域
- _Alignas
- typedef 声明
- 原子类型
- 外部及试探性定义
- inline 函数指定符
- _Noreturn 函数指定符
- 变长参数
- 内联汇编
- 可分析性
- 替用运算符及记号
- C 关键词
- 预处理器
- C 标准库头文件
- 类型支持
- 程序支持工具
- 变参数函数
- 错误处理
- 动态内存管理
- 日期和时间工具
- 字符串库
- 算法
- 数值
- 文件输入/输出
- 本地化支持
- 原子操作库
- 线程支持库
- 实验性 C 标准库
- 有用的资源
- 符号索引
- 注释
字符串字面量
原位构造指定字符数组类型的无名对象,在需要内嵌字符串到源代码中时使用。
语法
" s-char-sequence "
|
(1) | ||||||||
u8" s-char-sequence "
|
(2) | (C11 起) | |||||||
u" s-char-sequence "
|
(3) | (C11 起) | |||||||
U" s-char-sequence "
|
(4) | (C11 起) | |||||||
L" s-char-sequence "
|
(5) | ||||||||
其中
s-char-sequence | - | 零或多个字符,每个或为来自源字符集的多字节字符(不含 " 、 \ 及换行符),或为转义序列中定义的字符转义、十六进制转义、八进制转义或统一字符名 (C99 起)。
|
1) 字符串字面量:字面量的类型为 char[N] ,其中
N
是以执行窄编码的编码单元数计的字符串的大小,包括空终止符。以执行字符集从 s-char-sequence 中的下个字符初始化数组的每个 char
元素。2) UTF-8 字符串字面量:字面量的类型为 char[N] ,其中
N
是以 UTF-8 编码单元数计的字符串大小,包括空终止符。以 UTF-8 编码从 s-char-sequence 中的下个多字节字符初始化数组中的每个 char
元素。3) 16 位宽字符串字面量:字面量的类型为 char16_t[N] ,其中
N
是以实现定义的 16 位编码(通常为 UTF-16 )的编码单元数计的字符串大小,包括空终止符。如同通过在实现定义的本地环境中执行 mbrtoc16 初始化数组的每个 char16_t
元素。4) 32 位宽字符串字面量:字面量的类型为 char32_t[N] ,其中
N
是以实现定义的 32 位编码(通常为 UTF-32 )的编码单元数计的字符串大小,包括空终止符。如同通过在实现定义的本地环境中执行 mbrtoc32 初始化数组的每个 char32_t
元素。5) 宽字符串字面量:字面量的类型为 wchar_t[N] ,其中
N
是以执行宽编码的编码单元数计的字符串大小,包括空终止符。如同通过在实现定义的本地环境中执行 mbstowcs 初始化数组的每个 wchar_t
元素。解释
首先,在翻译阶段 6 (宏展开后),连接相邻的字符串字面量(即仅为空白符所分隔的字符串字面量)。
仅可连接二个窄或二个宽字符串字面量。 |
(C99 前) |
若一个字面量无前缀,则结果字符串字面量拥有有前缀字面量所指定的宽度/编码。若二个字符串字面量拥有不同的编码前缀,则连接是实现定义的。 L"Δx = %" PRId16 // 在阶段 4 , PRId16 展开成 "d" // 在阶段 6 , L"Δx = %" 和 "d" 组成 L"Δx = %d" |
(C99 起) |
其次,在翻译阶段 7 ,添加空终止字符到每个字符串字面量,然后每个字符串字面量初始化一个拥有静态存储期,长度刚好能容纳字符串字面量的内容加一个空终止符的无名数组。
char* p = "\x12" "3"; // 创建 static char[3] 数组,保有 {'\x12', '3', '\0'} // 设置 p 指向数组的首元素
字符串字面量不可修改(而且实际上可以放在例如 .rodata
的只读内存中)。若程序试图修改字符串字面量组成的静态数组,则行为未定义。
char* p = "Hello"; p[1] = 'M'; // 未定义行为 char a[] = "Hello"; a[1] = 'M'; // OK : a 不是字符串字面量
既不要求亦不禁止等同的字符串字面量指代内存中的同一位置。而且,重叠的字符串字面量或作为其他字符串字面量子串的字符串字面量可以结合。
"def" == 3+"abcdef"; // 可为 1 或 0 ,实现定义
注意
字符串字面量不必是一条字符串;若字符串字面量拥有内嵌的空字符,则它表示含有多于一条字符串的数组:
char* p = "abc\0def"; // strlen(p) == 3 ,但数组大小为 8
若在字符串字面量中合法十六进制数位后随十六进制转义,则这会作为非法的转义序列导致编译失败,但能以字符串连接为变通方式:
//char* p = "\xfff"; // 错误:十六进制转义在范围外 char* p = "\xff""f"; // OK :字面量为 char[3] ,保有 {'\xff', 'f', '\0'}
字符串字面量能用于初始化数组,而若数组大小比字符串字面量大小少一,则忽略空终止符:
char a1[] = "abc"; // a1 为 char[4] ,保有 {'a', 'b', 'c', '\0'} char a2[4] = "abc"; // a2 为 char[4] ,保有 {'a', 'b', 'c', '\0'} char a3[3] = "abc"; // a3 为 char[3] ,保有 {'a', 'b', 'c'}
字符串字面量 (1) 和宽字符串字面量 (5) 的编码是实现定义的。例如, gcc 用命令行选项 -fexec-charset 和 -fwide-exec-charset 选择它们。
示例
运行此代码
#include <stdio.h> #include <stdlib.h> #include <stddef.h> #include <uchar.h> #include <locale.h> int main(void) { char s1[] = "a猫????"; // 或 "a\u732B\U0001F34C" char s2[] = u8"a猫????"; char16_t s3[] = u"a猫????"; char32_t s4[] = U"a猫????"; wchar_t s5[] = L"a猫????"; setlocale(LC_ALL, "en_US.utf8"); printf(" \"%s\" is a char[%zu] holding { ", s1, sizeof s1 / sizeof *s1); for(size_t n = 0; n < sizeof s1 / sizeof *s1; ++n) printf("%#x ", +(unsigned char)s1[n]); puts(" }"); printf("u8\"%s\" is a char[%zu] holding { ", s2, sizeof s2 / sizeof *s2); for(size_t n = 0; n < sizeof s2 / sizeof *s2; ++n) printf("%#x ", +(unsigned char)s2[n]); puts(" }"); printf(" u\"a猫????\" is a char16_t[%zu] holding { ", sizeof s3 / sizeof *s3); for(size_t n = 0; n < sizeof s3 / sizeof *s3; ++n) printf("%#x ", s3[n]); puts(" }"); printf(" U\"a猫????\" is a char32_t[%zu] holding { ", sizeof s4 / sizeof *s4); for(size_t n = 0; n < sizeof s4 / sizeof *s4; ++n) printf("%#x ", s4[n]); puts(" }"); printf(" L\"%ls\" is a wchar_t[%zu] holding { ", s5, sizeof s5 / sizeof *s5); for(size_t n = 0; n < sizeof s5 / sizeof *s5; ++n) printf("%#x ", (unsigned)s5[n]); puts(" }"); }
可能的输出:
"a猫????" is a char[9] holding { 0x61 0xe7 0x8c 0xab 0xf0 0x9f 0x8d 0x8c 0 } u8"a猫????" is a char[9] holding { 0x61 0xe7 0x8c 0xab 0xf0 0x9f 0x8d 0x8c 0 } u"a猫????" is a char16_t[5] holding { 0x61 0x732b 0xd83c 0xdf4c 0 } U"a猫????" is a char32_t[4] holding { 0x61 0x732b 0x1f34c 0 } L"a猫????" is a wchar_t[4] holding { 0x61 0x732b 0x1f34c 0 }
引用
- C11 standard (ISO/IEC 9899:2011):
- 6.4.5 String literals (p: 70-72)
- C99 standard (ISO/IEC 9899:1999):
- 6.4.5 String literals (p: 62-63)
- C89/C90 standard (ISO/IEC 9899:1990):
- 3.1.4 String literals