当前位置: C语言 -- 专题 -- 字符串字面量

字符串字面量

C语言中字符串字面量(string literals)可以使用以下格式表示:

encoding-prefixopt"s-char-sequenceopt"

其中encoding-prefix是编码前缀,例如:u8、L、u、U;s-char-sequence是字符序列,两者都是可选的。

s-char-sequence中字符为源字符集的任何成员(双引号、反斜杠、换行符除外)或者转义序列。双引号、反斜杠、换行符可以使用转义序列表示,例如:\"、\\、\n。在字符串字面量中,单引号既可以使用字符'表示,也可以使用转义序列\'表示;但双引号只能使用转义序列\"表示。


字符字符串字面量(character string literal)无编码前缀;UTF-8字符串字面量存在编码前缀u8;wchar_t字符串字面量、UTF-16字符串字面量、UTF-32字符串字面量统称为宽字符串字面量(wide string literals)。宽字符串字面量(wide string literal)存在编码前缀L、u或者U。不同编码前缀对应的字符串字面量如下表所示:

字符串字面量前缀及其对应类型
类别 前缀 对应类型 示例
  字符字符串字面量 无   char *   "中国"
  UTF-8字符串字面量 u8   char8_t *   u8"中国"
  宽字符串字面量 L   wchar_t *   L"中国"
u   char16_t *   u"中国"
U   char32_t *   U"中国"

(注:如果实现定义了宏__STDC_UTF_16__,char16_t类型字符将使用UTF-16编码;如果实现定义了宏__STDC_UTF_32__,char32_t类型字符将使用UTF-32编码。有些实现中wchar_t类型和char16_t类型是兼容类型。)


字符字符串字面量是使用双引号括起来的0个或者至少一个多字节字符的序列,例如:""、"A"、"中秋节"。UTF-8字符串字面量和宽字符串字面量的构成方式与字符字符串字面量基本相同,唯一不同的是存在编码前缀u8、L、u或者U,例如:u8"\u4e2d\u56fd"、L"家"、u"\u4e2d\u79cb\u8282"、U"Hello"。

对于字符字符串字面量,序列中每个元素视为是一个整型字符常量;对于UTF-8字符串字面量,序列中每个元素视为是一个UTF-8字符常量;对于宽字符串字面量,序列中每个元素视为是一个宽字符常量。


字符串字面量的拼接

如果字符串字面量太长,C语言允许将字符串字面量分成多行来表示,一种方法就是在每行末尾使用反斜杠,例如:

printf("Genius is one percent inspiration and ninety-nine percent perspiration.\
Without the one percent of inspiration,\
all the perspiration in the world is only a bucket of sweat.\
    -- Thomas Edison");

字符串字面量会延续到下一行;每行开始处如果有空白字符,都是字符串字面量的一部分。使用这种方法,反斜杠后面只能有换行符,不能有其它字符。编译时编译器会将多行代码拼接成一个字符串字面量。


字符串字面量的串联

在编译阶段的第6个步骤,编译器会将相邻的字符串字面量串联成一个字符串字面量,例如:

"x" "y" "z"

将串联成

"xyz"

串联字符串字面量时,如果有一个字符串字面量有前缀,结果字符串字面量将具有相同的前缀,例如:

L"x" "y" "z"
L"x" L"y" "z"

上述两个例子的串联结果是相同的,均为

L"xyz"

相邻字符串字面量序列如果同时包含u8前缀的字符串字面量和宽字符字符串字面量(前缀为L、u或者U),这种行为是非法的,例如:

L"x" "y" u8"z"		//非法。

不同前缀的宽字符字符串字面量能否串联将由实现定义;如果可以串联,结果字符串字面量的处理也将由实现定义。


字符串字面量拼接和串联的比较

拼接和串联允许将一个长字符串字面量拆分成多行来表示,但在合并成一个字符串字面量时这两种方法还是有差异的,差异的主要原因是它们发生的先后顺序不一样。代码拼接发生在源字符转换成执行字符之前,相邻字符串字面量串联发生在源字符转换成执行字符之后。下面通过一个具体例子比较一下它们的差异。

printf("\12\
3");
printf("\12"
       "3");

将输出:

S

3

对于第一个输出是先拼接后转换,所以输出转义序列\123,在ASCII字符集中对应的是大写字母S。对于第二个输出是先转换后串联,在ASCII字符集中转义序列\12对应的是换行符,所以第二个输出是先输出换行符,再输出3。


字符串字面量的存储

在编译阶段的第7个步骤,编译器会在字符串字面量的末尾添加一个空字符('\0')(注:由于这个原因,字符串字面量不一定是字符串。),然后将这个序列存入一个具有静态存储期限的数组。以字符串字面量"China"为例,其存储形式如下所示:

C h i n a \0

数组中存有6个字符,即'C'、'h'、'i'、'n'、'a'、'\0',每个字符占1个字节空间。

如果字符串字面量为空,将只存储1个空字符。


由于字符串字面量的存储特点,字符串字面量可以用作地址运算符(&)和下标运算符([])的操作数,例如:

printf("%p\n", &"China");       
printf("%c\n", "China"[1]);     

如果试图修改字符串字面量,其行为是未定义的,例如:

"China"[0] = 'c';       //未定义行为。

值相同的字符串字面量是否具有相同的存储地址,ISO/IEC 9899:2018标准未作明确说明。



主要参考资料:

1、ISO/IEC 9899:2024

2、ISO/IEC 9899:2018