構造一個指定字符數組類型的未命名對象,用于需要在源代碼中嵌入字符串時使用。
句法
" s-char-sequence "(1)u8 " s-char-sequence "(2)(since C11)
u " s-char-sequence "(3)(since C11)
U " s-char-sequence "(4)(since C11)
L " s-char-sequence "(5)
其中
S-炭序列-零個或多個字符,每個字符可以是源字符集中的多字節字符(不包括(“),\和換行符),也可以是字符轉義,十六進制轉義,八進制轉義或統一字符名稱(自C99開始)在轉義序列中。
1)字符串文字:文字的類型是char[],數組中的每個字符都是使用執行字符集從s-char-sequence中的下一個字符初始化的。
2)UTF-8字符串文字:文字的類型是char[],數組中的每個字符都是使用UTF-8編碼從s-char-sequence中的下一個多字節字符初始化的。
3)16位寬字符串文字:文字的類型是char16_t[],數組中的每個char16_t元素都被初始化,就好像通過mbrtoc16在實現定義的區域設置中執行一樣。
4)32位寬的字符串文字:文字的類型是char32_t[],數組中的每個char32_t元素都被初始化,就好像通過mbrtoc32在實現定義的區域設置中執行一樣。
5)寬字符串文字:文字的類型是wchar_t[],數組中的每個wchar_t元素被初始化,就好像通過mbstowcs在實現定義的區域設置中執行一樣。
說明
首先,在翻譯階段6(宏擴展之后),將相鄰的字符串文字(即僅由空白分隔的字符串文字)連接起來。
只有兩個窄或兩個寬字符串可以連接在一起。(直到C99)如果一個文字沒有前綴,那么結果字符串文字的寬度/編碼由前綴文字指定。如果兩個字符串文字具有不同的編碼前綴,則連接是實現定義的。L“Δx=%”PRId16 //在階段4,PRId16在階段6擴展為“d”// L“Δx=%”和“d”形成L“Δx=%d”(自C99以來)
其次,在翻譯階段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
對于相同的字符串文字來說,既不要求也不禁止在存儲器中引用相同的位置。而且,重疊的字符串文字或者是其他字符串文字的子字符串的字符串文字可以組合。
"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?rangechar*?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。
例
#include?#include?#include?#include?#include?int?main(void){
char?s1[]?=?"a貓?";?//?or?"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?
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?
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?
printf("%#x?",?s3[n]);?puts("?}");????printf("?U\"a貓?\"?is?a?char32_t[%zu]?holding?{?",?sizeof?s4?/?sizeof?*s4);????for(size_t?n?=?0;?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?
printf("%#x?",?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??}