字面常量（literal constant），是 C 程式設計語言與 C 語言的詞法上的概念（lexical conventions），C2011 ISOIEC 14882 214 Literals 是指源程式中表示固定值的符號（token）。C11 標準 2141 的腳註 21：The term literal generally designates in this International Standard those tokens that are called constants in ISO C 即 C 語言的 constants 與 C 的 literal 是一碼事，屬於詞法分析時的 token。 下述內容遵從 C11 與 C11 語言標準。 整型字面常量 包括下述的數值進位制： 10 進位制： 如 1234 8 進位制：如 0373 16 進位制：如 0x2a7 2 進位制（從 C14 開始）：如 0b101 或者 0B0101 整型字面量轉化為整數型別表示，依照下述順序：C99 標準，第 6441 節，條款 5 int unsigned int long int unsigned long int long long int unsigned long long int 其中，10 進製表示的字面量僅考慮有符號的整數型別；而 8 進位制或 16 進位制的字面量先考慮能否用有符號的整數型別表示，如不能再考慮能否用同樣長度的無符號整數型別表示。例如，字面量 0x87654321，這是一個正值，用 4 位元組長的 int 無法表示，編譯器就會自動選用 unsigned int 來表示該字面量。 整型字面量可以使用字尾 u U ul UL ull ULL 明確表示各種無符號整型；使用字尾 l L ll LL 表示該字面量至少為 long 或為 long long 型。 C14 引入了千分位分隔符。例如： auto integer_literal 1000000 C14 還引入了二進位制字面量，例如： auto perm 0b100110111 浮點型字面常量 包括下述的數值進位制： 10 進位制：如 23 2e3 2e5 212e15 等。如果不是科學計數法形式，就必須有小數點，小數點前或後的數字可省略； 16 進位制（C 語言特有，C99 引入）：如 0x1p10（值為 102410） 0x10004p10（值為 1024062510）等。 沒有後綴的浮點型字面量具有 double 型別。使用字尾 f F l L 表示 float 或 long double 型別。 C14 引入了千分位分隔符。例如： auto dd 12345678 字元型字面常量 字元型字面量（character literal）是用單引號括起來的一個或多個字元，可選字首字元有 u、U、L。ISO 14882 《C14 specification》 section 2143 entry 1 沒有字首字元的稱為普通字元字面量 ordinary character literal 或窄字元字面常量（narrowcharacter literal） 只包含執行字元集（execution character set）中一個可表示字元的普通字元字面量，如：a，則其型別為 char，其值等於該字元在執行字元集中的編碼值。實際上，編譯器在 token 分析階段，通常就會把字元與字串在原始檔中的編碼串轉換為指定或者執行字元集的編碼串。 包含多個字元的普通字元字面常量，被稱為多字元字面量（multicharacter literal）。多字元字面量，以及包含執行字元集（execution character set）中一個不可表示字元的普通字元字面量，被有條件支援，具有型別 int，其值為實現定義。C99 語言規範 6444p10 有類似內容： The value of an integer character constant containing more than one character eg ab or containing a character or escape sequence that does not map to a singlebyte execution character is implementationdefined 各常見 CC 編譯器一般都支援如下例子： Multicharacter literals int m0 abcd int value 0x61626364 需要注意的是，在 C 語言中字元常量 a 具有 int 型別，sizeof a 等於 sizeof int；在 C 語言中字元字面量 a 具有 char 型別，sizeof a 為 1。 使用字首 L u U 分別表示 wchar_t char16_t char32_t 等字元型別的字面量。例如 uy。一個 wchar_t 型別的字面量的值，就是該字元在執行寬字元集（execution widecharacter set）中的編碼值；單如果該字元在執行寬字元集中不可表示，則其值是實現定義的。一個 char16_t 型別的字面量的值，就是該字元在 Unicode 編碼中的 16 位元的碼位；顯然該字元必須屬於 Unicode 中的基本多文種平面才能用 16 位元來編碼，否則程式是病態的。一個 char32_t 型別的字面量的值，就是該字元在 Unicode 編碼中的 32 位元的碼位。這些字元型別在 x86 平臺均為小端序表示。char16_t 字面量或 char32_t 字面量，如果包含多個字元，是病態的。wchar_t 字面量，如果包含多個字元，其值是實現定義的。 由於字元型字面量可能不屬於 CC 的 token 的字元範圍，這就需要用反斜線 開始的轉義序列來表示一個字元值： 簡單轉義序列： a b f n r t v 共計 11 個字元； 八進位制轉義序列：如 1 12 123 等等，直至不是八進位制數字為止，最多使用 3 位八進位制數字； 十六進位制轉義序列：如 x1abf4 ，可以使用任意多的十六進位制數字，直至不是十六進位制數字為止； 通用字元名（universecharacter name）：u 後面必須跟 4 個十六進位制數字（不足四位前面用零補齊），表示 Unicode 中在 0 至 0xFFFF 之內的碼位（但不能表示 0xD800 到 0xDFFF 之內的碼點，Unicode 標準規定這個範圍內的碼位保留，不表示字元）； 32 位的通用字元名：U 後面必須跟 8 個十六進位制數字（不足八位前面用零補齊），表示 Unicode 中所有可能的碼位（除 0xD800 到 0xDFFF 之外）。 上述兩種 Unicode 轉義序列的字元表示法，由編譯器自動轉換為相應的字元內部編碼格式。如為 wchar_t 字元。 如果字元字面量的值超過了 char、char16_t、char32_t、wchar_t 實現定義的範圍，那麼其值是實現定義的。例如，原始檔是 Latin1 編碼，執行字元集為 utf8，則 char cö 中的字元值將被編譯器從 Latin1 編碼的單位元組的 0xD6 自動轉為 utf8 編碼的雙位元組的 0xC3B6，在目標檔案與可執行檔案中字元 c 的值是 ö 的 utf8 編碼值的最後一個位元組值即 0xB6。 為支援老的程式碼，C 語言規定了三字元組替換，在掃描處理 C 語言原始檔時，替換下述的 3 字元出現為 1 個字元： 三字元組 替換為 如果希望在源程式中有兩個連續的問號，且不希望被預處理器替換，這種情況出現在字元字面常量、字串字面常量或者是程式註釋中，可選辦法是用字串的自動連線：或者轉義序列：。 從 Microsoft Visual C 2010 版開始，該編譯器預設不再自動替換三字元組。如果需要使用三字元組替換（如為了相容古老的軟體程式碼），需要設定編譯器命令列選項 Zctrigraphs gcc 預設不識別三字元組，並會給出編譯警告。在指定了 CC 標準時，gcc 才會識別三字元組，但仍會給出編譯警告。 字串字面常量 C 語言經典的 ASCII0 字串，例如 Hello world。 由 RsomeCharsopt 與someCharsopt 括起來的字串字面量叫做 raw string literal，這可以避免大量使用反斜線跳脫字元造成的令人眼花繚亂的傾斜牙籤綜合徵，特別適用於定義正則表示式的模式字串時。例如： stdstring filePath RCFooBartxt stdregex re Rabc s1g abc 如果字串包含了 這兩個字元的組合，可選別的分界符，如 abc。但這個分界符序列的長度最多 16。 字串字面量的值預設為工作字元集的編碼。具體是哪一種工作字元集編碼，由編譯器採用預設設定，如 Visual C 預設使用當前作業系統的預設內碼表，簡體中文 Windows 就是 gbk 編碼，Linux 上的 gcc 一般預設為 utf8 編碼；也可以作為命令列引數指定給編譯器，如 gcc 的 fexeccharset 使用編碼字首（encodingprefix）： u8 u U L 指出字串字面量的值為 UTF8、char16_t、char32_t、wchar_t 的編碼序列。例如， char ss u8Hi 世界ss 陣列內儲存的是 H、i、 世 、 界 這四個字元的 UTF8 的編碼值 相鄰的兩個字串將被編譯器自動連線為一個字串。如： char ss Hello world 列舉常量 列舉型別實質上是取有限個值的整型。根據 C 與 C98 標準，列舉常量屬於定義了列舉型別的那個作用域，而不屬於這個列舉型別的內部作用域。C 發明人 Bjarne Stroustrup 稱之為列舉常量的作用域不受限（unscoped）現象，這會造成命名衝突，與列舉常量是 有型別的常量 的初衷不符，與面向物件程式設計的原則嚴重相悖。例如： enum FileAccess Read 0x1 Write 0x2 FileAccess access Read 正確 FileAccess access FileAccessRead 錯誤 enum FileShare Read 0x1 重定義錯誤 Write 0x2 重定義錯誤 C11 為解決上述問題，引入了 列舉類（enum class）。在定義列舉型別時，enum 關鍵字後面加上 class 關鍵字（或 struct 關鍵字）；引用列舉常量時，必須加上列舉型別名使其為作用域限定 （scoped）。這避免了列舉常量的命名衝突；同時也避免了不同列舉型別的值的隱式型別轉換，從而保證了列舉型別是強型別（strongly typed）的。例如： enum class Color RED BLACK Color c ColorRED C11 還允許指定列舉型別的儲存型別，這使得列舉型別的前向宣告（forward declaration）成為可能。例如： enum class Color char forward declaration void foo Color p enum class Color char RED BLUE definition 布林型字面常量 有兩個 bool 型別的字面常量：true false 指標型字面常量 C11 定義了一個字面常量 nullptr，其型別是 stdnullptr_t。但 stdnullptr_t 既不是指標型別也不是到成員的指標型別。 使用者定義的字面量 C11 新增加了使用者定義的字面常量（user defined literal）。由使用者給出字面常量的字尾，並給出字面量運算子函式（或模板）的定義。編譯器可在執行期或編譯期把帶有這樣字尾的整型、浮點型、字元型、字串型的字面量透過呼叫使用者的字面量運算子函式（或模板），生成指定資料型別的物件。例如， includeiostream struct S int value S operator _mysuffix unsigned long long v 使用者定義字面量運算子的實現 S s_ s_valueint v return s_ int main S sv sv101_mysuffix 這裡的 101 是型別 S 的字面量 stdcoutsvvaluestdendl return 0 參考文獻 CategoryC 語言 CategoryC