字串字面量
在原位建構指定字元陣列類型的未命名物件,用於原始程式碼中需要嵌入字串時。
目錄 |
[編輯] 語法
" 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++ 文件 關於 字串實體
|