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

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

賦值:左值和右值

一些語言使用左值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程式語言的一篇論文引入。[3] 這時定義的左值是可以放在賦值號左側賦予新值的對象;[4]右值是可以放在賦值號右側讀出其值的對象。在B語言中,左值和右值作為文法的元素被明確。在C語言中,文法不再出現左值和右值的區別,左值的概念被保留在語意規則中,而「右值」在ISO C中被視為「值」的同義詞。

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

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

  • 基礎值類型
    • 左值lvalue:可以用取地址運算子&取得地址的表達式。也可定義為非臨時對象或非成員函數。具有標識,但不抽取式。這也是C++03的經典左值。可用於初始化左值參照。可以有不完備類型(incomplete type)。包括:
      • 作用域中的變數名與函數名,不論其類型。因此,具名的右值參照,即具有右值參照類型的變數,也是左值表達式,這符合一般規律,不是特例。
      • 函數呼叫表達式或多載運算子表達式,如果其返回類型為左值參照或者是到函數類型的右值參照。 [6]
      • 內建的先增(字首++)、先減(字首--)、解除參照(dereference)、賦值、複合賦值、下標(除了陣列臨終值)、成員訪問(除了臨終值的非靜態非參照成員、成員列舉值、非靜態成員函數),通過數據成員指標的訪問且左端運算元為左值、逗號運算子且右端的運算元為左值、三元條件運算子(ternary conditional)且第二與第三運算元為左值。
      • 到左值參照類型的類型轉換表達式。
      • 字串字面量(string literal)
      • 類型轉換表達式,轉換為到函數的右值參照
    • 臨終值xvalue(expiring value):具有標識,並且可以移動。對應的對象接近生存期結束,但其內容尚未被移走。可以多型;非類對象可以cv限定。包括:
      • 函數呼叫或多載的運算子表達式,如果返回類型是到對象的右值參照[6]
      • 類型轉換表達式,轉換為右值參照,如static_cast<T&&>(val)或(T&&)val
      • 訪問xvalue的非靜態類別成員。
      • 指向數據成員的指標表達式,第一運算元是xvalue
    • 純右值prvalue:不具有標識,但可以移動。對應臨時對象或不對應任何對象的值。純右值不能是多型的;臨時對象的動態型別是表達式類型;非類且非陣列的純右值不能是const限定的;不能有不完備類型(除了void)。包括:
      • 字面量(除了字串字面量)。
      • 函數呼叫或多載的運算子表達式,如果返回類型不是參照。[6]
      • 內建後增、後減、算術與邏輯運算子、比較運算子、取地址運算子、訪問成員列舉值、訪問非靜態成員函數、訪問右值的非靜態非參照數據成員、訪問右值的數據成員指標或非靜態函數成員指標、逗號運算子且右端運算元為右值、三元條件運算子且第二或第三運算元不是左值。
      • 類型轉換表達式,轉換為非參照類型。
      • 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是一樣的。字串的位元組序在不同處理器之間可能不同,取決於組譯器和電腦架構。

參考資料

外部連結

Wikiwand in your browser!

Seamless Wikipedia browsing. On steroids.

Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.

Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.