搜尋

首頁  >  問答  >  主體

c++ - 赋值语句中关于左值和右值的疑惑

对于左值和右值还有一些模糊的地方:

书上说左值(L-value)是指地址值,右值(R-value)是指数据值。
但对于***右值指的是引用了一个存储在某个内存地址里的数据***这句话不是特别清楚,比如说:a = 5, 
                1、数值5是来自于内存中的某个特定存储区域吗,而且无论数值大小均是这么来的吗(记忆中好像不是的呢)?
                2、使用数值5的时候是以copy的方式还是其他的方式得到的?
                3、或者是在赋值之前临时创建的大小为int的空间来存储5,并非是从内存中的引用?
                4、关于这方面有什么相关的书籍推荐么?
                

先谢谢各位不吝赐教。

高洛峰高洛峰2803 天前665

全部回覆(5)我來回復

  • PHPz

    PHPz2017-04-17 13:29:56

    這種常數都在程式碼段裡(.text section)。
    推薦: 深入理解電腦系統

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-17 13:29:56

    C語言不是很精通,但還是在此說一下自己的理解,如有不正確請指出。

    1. 個人覺得,「右值」不應該只是指記憶體位址中的資料。例如a = 5, 5就是一個直接數而非記憶體位址,正如彙編中可以直接往暫存器中寫直接數,也可以寫記憶體位址中的數一樣。因為對這種直接數取位址的話是沒有意義的。

    2. 我只知道java中的String在直接賦值為字串時,該字串是共享常數池中的字串的,但是C語言中不知道有沒有類似的機制。對於a = 5這種賦值來說應該和直接的立即數寫入差不多;而對於int a;int b = 5; a = b;這種賦值來說應該是拷貝無疑。這時b就是「引用了某個記憶體位址裡的資料」。

    3. 個人覺得對於這種簡單賦值來說臨時創建空間存儲然後拷貝過去在實現上看應該沒有必要(沒有求證過)。

    4. 平常不用C,而且本人學習不深,無法給出有價值的推薦。

    以上都是個人見解,沒有求證過,供題主參考。如有錯誤還請指出。

    回覆
    0
  • 大家讲道理

    大家讲道理2017-04-17 13:29:56

    不曉得你看的什麼書,我不大明白這個地址值和資料值的定義

    一个左值可能是一个函数或者对象。
    一个右值可能是一个对象、临时对象或者临时对象的子对象、或者不是对象的值
    具体可以参阅标准3.10小节,讲的就是左值与右值

    至於5所在的記憶體位置,對於這種整數來說,對於編譯器來講一般都是使用立即數直接賦值,5並沒有臨時存在於什麼地方,
    就像是把5放在a所在的堆疊上的位置,那麼這句話就是a = 5;
    如果是字串,有可能儲存在其他位置例如程式碼段,然後拷貝過來,這樣就是str = "123143";

    回覆
    0
  • 怪我咯

    怪我咯2017-04-17 13:29:56

    其他的我不是很懂
    但是:
    左值和右值都是針對表達式而言的,左值是指表達式結束後依然存在的持久對象,右值是指表達式結束時就不再存在的臨時物件。
    一個區分左值與右值的便利方法是:看能不能對表達式取位址,如果能,則為左值,否則為右值

    回覆
    0
  • 阿神

    阿神2017-04-17 13:29:56

    不太清楚題主問的是 C 還是 C++,如果是 C++ 的話,是哪一版標準的 C++。我這裡只說 C++11 中關於左值和右值的問題。

    粗略的來講,當一個物件被用作右值(rvalue)的時候,使用的是這個物件的值(它的內容);當一個物件被用作左值(lvalue)的時候,使用的是這個物件的身份(它在記憶體中的位置)。

    對於表達式a = 5;,假設aint型別。其中等號左邊的表達式a的型別是左值,因為我們需要用到它的身份(它在記憶體中的位置),才能把值賦給它。等號右邊的表達式5的型別是右值,因為我們需要用到它的值(它的內容)。

    1、數值5是來自於記憶體中的某個特定儲存區域嗎,而且無論數值大小均是這麼來的嗎(記憶中好像不是的呢)?

    數值5是 一個 literal,它的型別是右邊值(更精確的說是 prvalue,見下文),應該是保存在靜態記憶體(static memory)中。無論大小,只要是 literal 都是如此,例如 2333333333333333ULL

    2、使用數值5的時候是以copy的方式還是其他的方式得到的?

    在表達式a = 5;中,應該是內建賦值運算子將5從靜態記憶體複製到變數a中。

    對於自訂的賦值運算符,就要看:1. 是否定義了拷貝賦值運算子(copy-assignment operator)和移動賦值運算子(move-assignment operator),2. 等號右側表達式的值類型,從而確定是拷貝還是移動。

    3、或者是在賦值之前暫時創建的大小為int的空間來存儲5,並非是從內存中的引用?

    不是。

    4、關於這方面有什麼相關的書籍推薦麼?

    不清楚有沒有專門論述這方面的書籍,不過你可以看看本文末尾參考部分的文檔和 C++11 標準。


    以下為引申內容。

    前提

    C++ 中的表達式(expression,例如操作符和它的操作數、變數名稱等)是根據兩個方面進行分類的:類型值類別。每個表達式必定屬於三個主要值類別(見下文)之一。

    C++11 中表達式的值類別

    在C++11 之前,表達式的值類別分為左值(lvalue)和右值(rvalue)兩種,而自C++11 起,表達式的值類別分為lvalue、xvalue、 prvalue、glvalue、rvalue 五種。之所以引入了這麼多種值類型,是因為 C++11 中新增的移動語意(move semantics)。

    他們之間的關係如下圖:

               expression
                   |
            +------+-------+
            |              |
            v              v
         glvalue         rvalue        <-- 混合值类别(mixed value categories)
            |              |
      +-----+-----+  +-----+-----+
      |           |  |           |
      v           v  v           v
    lvalue       xvalue       prvalue  <-- 主要值类别(primary value categories)

    表達式的值類別分類的標準是兩點:

    • 有無身份(has identity) 即是否能透過比較兩個表達式的身份來判斷他們是否是同一個表達式。

    • 能否被移走(can be moved from) 即能把表達式的值移到其它變數中去,使原變數處於不確定但有效的狀態(例如能正常析構)。

    這5個數值類別之間的關係如下表所示:

    |   value    | has identity | can be moved from |
    +============+==============+===================+
    |   lvalue   |     yes      |        no         |
    |   xvalue   |     yes      |        yes        |
    |  prvalue   |     no       |        yes        |
    | (not used) |     no       |        no         |
    +------------+--------------+-------------------+
    |  glvalue   |     yes      |        ?          | pre-C++11 lvalue
    |   rvalue   |     ?        |        yes        | pre-C++11 rvalue

    C++11 標準原文

    From C++11 standard § 3.10

    — An lvalue (so called, historically, because lvalues could appear on the left-hand side of an assignment expression) designates a function or an object. expression of pointer type, then *E is an lvalue expression referring to the object or function to which E points. As another example, the result of calling a function whose return type is an lvalue reference is value reference. >— An
    xvalue (an “eXpiring” value) also refers to an object, usually near the end of its lifetime (so that its resources may be moved, for example). An xvalue kinds of expressions involving rvalue references (8.3.2). [ Example: The result of calling a function whose return type is an rvalue reference is an x​​value. —end example ]— A < <7. generalized” lvalue) is an lvalue or an x​​value.
    — An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment exue), x. object (12.2) or subobject thereof, or a value that is not associated with an object.
    — A prvalue (“pure” rvalue) is 🎜>prvalue
    (“pure” rvalue) is an rvalue thatan notn an x​​. result of calling a function whose return type is not a reference is a prvalue. The value of a literal such as 12, 7.3e5, or true is also a prvalue. —end example ]

    參考

      C++ 中表達式的值的類別:Value categories
    • C++ 中值分類名稱的變化由來:「New」 Value Terminology
    • C++0x 到 C++11 值分類名稱的變化:n3055
    • 回覆
      0
  • 取消回覆