命名空间
变体
操作

字符串字面量

来自 cppreference.com
< 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 是字符串在执行窄编码中的代码单元大小,包括空终止符。数组中的每个 char 元素都使用执行字符集从 s-char-sequence 中的下一个字符进行初始化。
2) UTF-8 字符串字面量:字面量的类型为 char[N](直到 C23)char8_t[N](自 C23 起),其中 N 是字符串在 UTF-8 代码单元中的大小,包括空终止符。数组中的每个 char(直到 C23)char8_t(自 C23 起) 元素都使用 UTF-8 编码从 s-char-sequence 中的下一个多字节字符进行初始化。
3) 16 位宽字符串字面量:字面量的类型为 char16_t[N],其中 N 是字符串在实现定义的 16 位编码(通常为 UTF-16)中的代码单元大小,包括空终止符。数组中的每个 char16_t 元素都使用在实现定义的区域设置中执行 mbrtoc16 的方式进行初始化。
4) 32 位宽字符串字面量:字面量的类型为 char32_t[N],其中 N 是字符串在实现定义的 32 位编码(通常为 UTF-32)中的代码单元大小,包括空终止符。数组中的每个 char32_t 元素都使用在实现定义的区域设置中执行 mbrtoc32 的方式进行初始化。
(直到 C23)
3) UTF-16 字符串字面量:字面量的类型为 char16_t[N],其中 N 是字符串在 UTF-16 代码单元中的大小,包括空终止符。数组中的每个 char16_t 元素都使用 UTF-16 编码从 s-char-sequence 中的下一个多字节字符进行初始化。
4) UTF-32 字符串字面量:字面量的类型为 char32_t[N],其中 N 是字符串在 UTF-32 代码单元中的大小,包括空终止符。数组中的每个 char32_t 元素都使用 UTF-32 编码从 s-char-sequence 中的下一个多字节字符进行初始化。
(自 C23 起)
5) 宽字符串字面量:字面量的类型为 wchar_t[N],其中 N 是字符串在执行宽编码中的代码单元大小,包括空终止符。数组中的每个 wchar_t 元素都使用在实现定义的区域设置中执行 mbstowcs 的方式进行初始化。

[编辑] 解释

首先,在 翻译阶段 6(宏展开之后),相邻的字符串字面量(即仅由空格分隔的字符串字面量)将被连接。

只能连接两个窄字符串字面量或两个宽字符串字面量。

(直到 C99)

如果一个字面量没有前缀,则结果字符串字面量将具有前缀字面量指定的宽度/编码。

L"Δx = %" PRId16 // at phase 4, PRId16 expands to "d"
                 // at phase 6, L"Δx = %" and "d" form L"Δx = %d"
(自 C99 起)

如果两个字符串字面量具有不同的编码前缀,则连接是实现定义的,但 UTF-8 字符串字面量和宽字符串字面量不能连接。

(自 C11 起)
(直到 C23)

如果两个字符串字面量具有不同的编码前缀,则连接是非法的。

(自 C23 起)

其次,在 翻译阶段 7,每个字符串字面量都将添加一个终止空字符,然后每个字面量都将用静态 存储期 和正好足以包含字符串字面量内容加上空终止符的长度的未命名数组进行初始化。

char* p = "\x12" "3"; // creates a static char[3] array holding {'\x12', '3', '\0'}
                      // sets p to point to the first element of the array

字符串字面量是不可修改的(实际上可能放置在只读内存中,例如 .rodata)。如果程序试图修改由字符串字面量形成的静态数组,则行为未定义。

char* p = "Hello";
p[1] = 'M'; // Undefined behavior
char a[] = "Hello";
a[1] = 'M'; // OK: a is not a string literal

对于相同的字符串字面量是否引用内存中的相同位置,既没有要求也没有禁止。此外,可以合并重叠的字符串字面量或作为其他字符串字面量的子字符串的字符串字面量。

"def" == 3+"abcdef"; // may be 1 or 0, implementation-defined

[编辑] 说明

字符串字面量不一定是字符串;如果字符串字面量包含嵌入的空字符,则它表示一个包含多个字符串的数组。

char* p = "abc\0def"; // strlen(p) == 3, but the array has size 8

如果字符串字面量中的十六进制转义后面是有效的十六进制数字,则编译将失败,因为它是无效的转义序列,但字符串连接可以用作解决方法。

//char* p = "\xfff"; // error: hex escape sequence out of range
char* p = "\xff""f"; // okay, the literal is char[3] holding {'\xff', 'f', '\0'}

字符串字面量可用于 初始化数组,如果数组的大小比字符串字面量的大小少 1,则将忽略空终止符。

char a1[] = "abc"; // a1 is char[4] holding {'a', 'b', 'c', '\0'}
char a2[4] = "abc"; // a2 is char[4] holding {'a', 'b', 'c', '\0'}
char a3[3] = "abc"; // a3 is char[3] holding {'a', 'b', 'c'}

字符字符串字面量 (1) 和宽字符串字面量 (5) 的编码是实现定义的。例如,gcc 使用 命令行选项 -fexec-charset-fwide-exec-charset 进行选择。

虽然 C11 中允许混合宽字符串字面量连接,但几乎所有编译器都拒绝这种连接(已知的唯一例外是 SDCC),并且其使用体验尚不清楚。因此,在 C23 中移除了对混合宽字符串字面量连接的允许。

[编辑] 示例

#include <inttypes.h>
#include <locale.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <uchar.h>
 
int main(void)
{
    char s1[] = "a猫🍌"; // or "a\u732B\U0001F34C"
#if __STDC_VERSION__ >= 202311L
    char8_t
#else
    char
#endif
    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("0x%02X ", +(unsigned char)s1[n]);
    puts("}");
    printf(
#if __STDC_VERSION__ >= 202311L
    "u8\"%s\" is a char8_t[%zu] holding  { "
#else
    "u8\"%s\" is a char[%zu] holding     { "
#endif
, s2, sizeof s2 / sizeof *s2);
    for(size_t n = 0; n < sizeof s2 / sizeof *s2; ++n)
#if __STDC_VERSION__ >= 202311L
       printf("0x%02X ", s2[n]);
#else
       printf("0x%02X ", +(unsigned char)s2[n]);
#endif
    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("0x%04" PRIXLEAST16" ", 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("0x%08" PRIXLEAST32" ", 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("0x%08X ", (unsigned)s5[n]);
    puts("}");
}

可能的输出

  "a猫🍌" is a char[9] holding     { 0x61 0xE7 0x8C 0xAB 0xF0 0x9F 0x8D 0x8C 0x00 }
u8"a猫🍌" is a char[9] holding     { 0x61 0xE7 0x8C 0xAB 0xF0 0x9F 0x8D 0x8C 0x00 }
 u"a猫🍌" is a char16_t[5] holding { 0x0061 0x732B 0xD83C 0xDF4C 0x0000 }
 U"a猫🍌" is a char32_t[4] holding { 0x00000061 0x0000732B 0x0001F34C 0x00000000 }
 L"a猫🍌" is a wchar_t[4] holding  { 0x00000061 0x0000732B 0x0001F34C 0x00000000 }

[编辑] 参考文献

  • C23 标准 (ISO/IEC 9899:2024)
  • 6.4.5 字符串字面量 (p: TBD)
  • C17 标准 (ISO/IEC 9899:2018)
  • 6.4.5 字符串字面量 (p: 50-52)
  • C11 标准 (ISO/IEC 9899:2011)
  • 6.4.5 字符串字面量 (p: 70-72)
  • C99 标准 (ISO/IEC 9899:1999)
  • 6.4.5 字符串字面量 (p: 62-63)
  • C89/C90 标准 (ISO/IEC 9899:1990)
  • 3.1.4 字符串字面量

[编辑] 另请参阅

C++ 文档 针对 字符串字面量