值類別
C 中的每個表示式(運算子及其引數、函式呼叫、常量、變數名等)都由兩個獨立的屬性來描述:型別和值類別。
每個表示式都屬於以下三種值類別之一:左值、非左值物件(右值)和函式指示符。
目錄 |
[編輯] 左值表示式
左值表示式是任何物件型別(除了void
型別)的表示式,它可能指代一個物件(如果在求值時左值實際上沒有指代一個物件,則行為未定義)。換句話說,左值表示式求值為物件標識。此值類別的名稱(“左值”)是歷史性的,它反映了左值表示式在 CPL 程式語言中作為賦值運算子左側運算元的使用。
左值表示式可以在以下左值上下文中使用
如果左值表示式在除了sizeof
、_Alignof
或上面列出的運算子之外的任何上下文中使用,任何完整型別的非陣列左值都會經歷左值轉換,這模擬了從物件位置載入值的記憶體操作。類似地,陣列左值在除了sizeof
、_Alignof
、取地址運算子或從字串字面量初始化陣列之外的任何上下文中都會經歷陣列到指標轉換。
const
/volatile
/restrict
-限定符和原子型別的語義僅適用於左值(左值轉換會去除限定符並移除原子性)。
以下表達式是左值
- 識別符號,包括函式命名引數,前提是它們被宣告為指代物件(而不是函式或列舉常量)
- 字串字面量
- (C99) 複合字面量
- 如果未加括號的表示式是左值,則加括號的表示式
- 如果成員訪問(點)運算子的左側引數是左值,則其結果
- 透過指標
->
運算子的成員訪問結果 - 應用於物件指標的間接(一元
*
)運算子的結果 - 下標運算子(
[]
)的結果
[編輯] 可修改左值表示式
可修改左值是任何完整、非陣列型別且未被const-限定的左值表示式,如果它是結構體/聯合體,則遞迴地,其成員中沒有const-限定的成員。
只有可修改左值表示式才能用作增量/減量運算子的引數,以及賦值和複合賦值運算子的左側引數。
[編輯] 非左值物件表示式
被稱為右值,非左值物件表示式是物件型別的表示式,它們不指代物件,而是指沒有物件標識或儲存位置的值。不能獲取非左值物件表示式的地址。
以下表達式是非左值物件表示式
- 整型、字元和浮點常量
- 所有未指定返回左值的運算子,包括
- 任何函式呼叫表示式
- 任何型別轉換表示式(注意:看起來相似的複合字面量是左值)
- 應用於非左值結構體/聯合體的成員訪問(點)運算子,f().x, (x,s1).a, (s1=s2).m
- 所有算術、關係、邏輯和位運算子的結果
- 增量和減量運算子的結果(注意:在 C++ 中,字首形式是左值)
- 賦值運算子的結果(注意:在 C++ 中也是左值)
- 條件運算子(注意:在 C++ 中,如果第二個和第三個運算元都是相同型別的左值,則是左值)
- 逗號運算子(注意:在 C++ 中,如果第二個運算元是左值,則是左值)
- 取地址運算子,即使透過應用於一元
*
運算子的結果而被中和
作為一個特殊情況,void
型別的表示式被假定為非左值物件表示式,它們產生一個沒有表示且不需要儲存的值。
請注意,具有陣列型別成員(可能巢狀)的結構體/聯合體右值確實指代一個具有臨時生命週期的物件。可以透過索引陣列成員或透過陣列成員的陣列到指標轉換獲得的指標進行間接訪問來訪問此物件。
[編輯] 函式指示符表示式
函式指示符(由函式宣告引入的識別符號)是函式型別的表示式。當在除了取地址運算子、sizeof
和_Alignof
(後兩個應用於函式時會產生編譯錯誤)之外的任何上下文中使用時,函式指示符總是轉換為非左值函式指標。請注意,函式呼叫運算子是為函式指標定義的,而不是為函式指示符本身定義的。
[編輯] 參考文獻
- C17 標準 (ISO/IEC 9899:2018)
- 6.3.2.1 左值、陣列和函式指示符 (p: 40)
- C11 標準 (ISO/IEC 9899:2011)
- 6.3.2.1 左值、陣列和函式指示符 (p: 54-55)
- C99 標準 (ISO/IEC 9899:1999)
- 6.3.2.1 左值、陣列和函式指示符 (p: 46)
- C89/C90 標準 (ISO/IEC 9899:1990)
- 3.2.2.1 左值和函式指示符
[編輯] 另請參閱
C++ 文件,關於值類別
|