左值

在電腦科學中，**值**（英語：Value）是一無法進一步求值的表達式。例如，表達式「1 + 2」不是一個值，因為它可以被化簡為表達式「3」。表達式「3」不能夠繼續化簡，因此它是一個值。表達式既有類型（type）屬性，又有值分類（value categories）屬性。兩種屬性彼此獨立。也就是說，對每一種類型的表達式，都有各種值分類。

大多數程式語言支援幾種常見的值。

## 賦值：左值和右值

一些語言使用**左值**（l-value）和**右值**（r-value）的概念。左值具有確定的、可以被獲得的記憶體位址。這意味著左值可以是變數，也可以是對指向特定記憶體位址的指標解除參照（dereference）的結果。例如 C 語言的表達式 `(4 + 9)`，在執行時，電腦生成一個整數值 13，但因為程式沒有明確指定這個 13 如何在電腦中儲存，所以這個表達式產生一個右值。另一方面，如果一個 C 程式聲明了一個變數 x 並將 x 賦值為 13，那麼表達式 `(x)` 的值是 13，並且是一個左值。

在 C 語言中，術語「左值」最初表示可以被賦值（即位於設定運算子左側）的物件，但由於「const」被加入到語言中，這類物件現在被稱作「可更改的左值」。C++ 中，左值和右值是表達式的分類，一個表達式必然是左值或右值之一。C++11 把上述左值性 (lvalueness) 擴充為更複雜的值類別 (value category)，包含左值（lvalue），純右值（prvalue）和臨終值（xvalue）三個基本分類 (fundamental classification)，一個表達式必然是三者之一。

左值和右值的概念最早由 CPL 程式語言的一篇論文引入。 這時定義的左值是可以放在賦值號左側賦予新值的物件；右值是可以放在賦值號右側讀出其值的物件。在 B 語言中，左值和右值作為文法的元素被明確。在 C 語言中，文法不再出現左值和右值的區別，左值的概念被保留在語意規則中，而「右值」在 ISO C 中被視為「值」的同義詞。

C++ 語言引入了 const 限定的物件。const 物件可以取位址，但是不能被賦值；而一些右值物件也可以出現在賦值號的左邊被賦值。因此，截至 C++03 標準，把具有標識（identity）的表達式規定為左值，不具有標識的表達式規定為右值。因而，名字、指標、參照等是左值，是命名物件，具有確定的記憶體位址；字面量、臨時物件等為右值，右值僅在建立它的表達式中可以被存取。函式名字是左值（在 C 語言中規定它既不是左值也不是右值），陣列名是常數左值，但是在大多數表達式中函式名字與陣列名字自動隱式轉換為右值。右值的生存期短暫，所以需要用左值去捕捉右值。把右值複製（copy）到左值上是常見操作。

C++11 標準引入了右值參照資料類型與移動語意，因而左值與右值的定義發生了很大變化。右值參照變數繫結到右值上，延長了右值對應的臨時物件的生存期。移動語意把臨時物件的內容移動（move）到左值物件上。因而在 C++11，對於值的分類，要考慮標識（identity）與抽取式性（movability），二者的組合產生了五種分類：

* 基礎值類型
  * 左值 lvalue：可以用取位址運算子 & 取得位址的表達式。也可定義為非臨時物件或非成員函式。具有標識，但不抽取式。這也是 C++03 的經典左值。可用於初始化左值參照。可以有不完備類型（incomplete type）。包括：
    * 作用域中的變數名與函式名，不論其類型。因此，具名的右值參照，即具有右值參照類型的變數，也是左值表達式，這符合一般規律，不是特例。
    * 函式呼叫表達式或多載運算子表達式，如果其返回類型為左值參照或者是到函式類型的右值參照。
    * 內建的先增（字首 ++）、先減（字首 --）、解除參照（dereference）、賦值、複合賦值、下標（除了陣列臨終值）、成員存取（除了臨終值的非靜態非參照成員、成員列舉值、非靜態成員函式），通過資料成員指標的存取且左端運算元為左值、逗號運算子且右端的運算元為左值、三元條件運算子（ternary conditional）且第二與第三運算元為左值。
    * 到左值參照類型的類型轉換表達式。
    * 字串字面量（string literal）
    * 類型轉換表達式，轉換為到函式的右值參照
  * 臨終值 xvalue（expiring value）：具有標識，並且可以移動。對應的物件接近生存期結束，但其內容尚未被移走。可以多型；非類物件可以 cv 限定。包括：
    * 函式呼叫或多載的運算子表達式，如果返回類型是到物件的右值參照。
    * 類型轉換表達式，轉換為右值參照，如 static\_cast<T&&>(val) 或 (T&&) val
    * 存取 xvalue 的非靜態類別成員。
    * 指向資料成員的指標表達式，第一運算元是 xvalue
  * 純右值 prvalue：不具有標識，但可以移動。對應臨時物件或不對應任何物件的值。純右值不能是多型的；臨時物件的動態型別是表達式類型；非類且非陣列的純右值不能是 const 限定的；不能有不完備類型（除了 void）。包括：
    * 字面量（除了字串字面量）。
    * 函式呼叫或多載的運算子表達式，如果返回類型不是參照。
    * 內建後增、後減、算術與邏輯運算子、比較運算子、取位址運算子、存取成員列舉值、存取非靜態成員函式、存取右值的非靜態非參照資料成員、存取右值的資料成員指標或非靜態函式成員指標、逗號運算子且右端運算元為右值、三元條件運算子且第二或第三運算元不是左值。
    * 類型轉換表達式，轉換為非參照類型。
    * Lambda 表達式
* 廣義左值 glvalue：具有標識。包括左值與臨終值。可以多型、動態型別。
* 右值 rvalue：可以移動。包括瀕死值與純右值。不能通過 & 運算子取位址。

C++ 的非靜態成員函式呼叫表達式（obj.func 與 ptr->func），非靜態成員函式指標呼叫表達式（obj.\*mfp 與 ptr->\*mfp）被當作純右值，但是不能用於初始化參照，不能做函式實參，僅僅能用作函式呼叫表達式左邊的運算元，如 (pobj->\*ptr)(args)。

返回 void 的函式呼叫表達式、到 void 的類型轉換表達式、throw 表達式被當作純右值。但是不能用於初始化參照，不能做函式實參。可用於某些上下文環境中（如單獨作為一行語句、逗號運算子的左端表達式等），或返回 void 的函式的 return 語句中。此外，throw 表達式可用作三元條件運算子的第二或第三運算元。

位元欄（bit field）表達式是左值，但不能用 & 運算子取位址，不能繫結到非常數左值參照。常數左值參照可以用位域左值初始化，但實際上是另行分配繫結了一個物件。

## 組合語言

值可以是一個給定的資料類型，例如一個字串，一個數字，一個單一的字母等幾乎任何類型的資料。

有些處理器支援多種尺寸的立即數，例如 8 位元或 16 位元，每一種指令形式採用獨特的操作碼和輔助記憶碼。如果一個程式設計師提供的資料值不適合，組譯器將會出現「超出範圍」的錯誤訊息。大多數組譯器允許一個立即數被表示為 ASCII，十進位，十六進位，八進位或二進位資料。因此，ASCII 字元 'A' 和 65、0x41 是一樣的。字串的位元組序在不同處理器之間可能不同，取決於組譯器和電腦架構。

## 參考資料

## 外部連結

* Value Object（頁面存檔備份，存於網際網路檔案館）
* Transfer Object Pattern （頁面存檔備份，存於網際網路檔案館）