字串字面量
就地構造一個指定字元陣列型別的無名物件,用於將字串嵌入原始碼中。
目錄 |
[編輯] 語法
" 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 開始),定義參見轉義序列。 |
N
是字串在執行窄編碼中的程式碼單元大小,包括空終止符。陣列中的每個 char 元素都使用執行字元集從 s-char-sequence 中的下一個字元初始化。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 起) |
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'}
字串字面量可用於初始化陣列,如果陣列的大小比字串字面量的大小小一,則空終止符將被忽略。
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: 待定)
- 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++ 文件,關於字串字面量
|