lvalue和rvalue、傳值和傳引用、木桶

來源:互聯網
上載者:User

http://gideshi.blog.163.com/blog/static/8991803420081118115951620/

在ddj上看到一篇文章,針對初學者,不過我覺得還是有一定的難度的。本來想翻譯過來,想想工作量會非常大,乾脆結合自己的知識,總結幾句。有興趣的話可以參考原文“Computer Programming and Precise Terminology”。文中闡述了定義和聲明的區別,寫得很精彩,讓大家瞭解了一些internals。由於我寫過一篇相關的文章,因此這裡不再囉嗦,想看的話可以參考“[原]C/C++:如何理解複雜的聲明”。

lvalue和rvalue
在電腦的遠古時代,變數的lvalue和rvalue是指:
lvalue:變數在記憶體中的位置。通過它能夠找到記憶體中存放的變數(location value);
rvalue:存放在lvalue對應的記憶體中的東西(register value);

變數的lvalue的存在表明有儲存空間,然而其rvalue並沒有對應儲存空間,它只是那片儲存空間對應的值。如果不考慮類型的話,那個就是一個1和0的序列。

好了,我們來看看:

// Allocate 4 bytes on stack and set content to 10.
int i = 10;

例1

i的lvalue和rvalue如下(假定i在記憶體中的地址為0x1000):
   lvalue        rvalue
   --------      -------
   |0x1000|      | 10  |
   --------      -------
-〉|字長    |<-  ->|int  |<-

圖1 i的lvalue和rvalue

對於:

// Allocate a machine word on stack and set content to NULL.
int *p = NULL;

// Allocate 4 bytes on heap and set content to 10, then set p's rvalue to the start address of these bytes.
p = new int(10);

例2

p的lvalue、rvalue以及真正的值如下(假定p的地址為0x1008):
  lvalue        rvalue
  --------      --------      -------
  |0x1008|      |0x5000|      | 10  |
  --------      --------      -------
-〉|字長    |<-  ->| 字長   |<-  ->|int  |<-

圖2 p的lvalue和rvalue  lvalue        rvalue
  --------      -------
  |0x5000|      | 10  |
  --------      -------
->| 字長   |<-  ->|int  |<-圖3 *p的lvalue和rvalue

傳值和傳引用
一個引用變數只能有取兩種值的rvalue:NULL和記憶體位址。在傳值時傳遞的是rvalue,傳引用則傳遞lvalue。也就是說:

int foo(int i);

int main()
{
    int i = 10;
    return foo(i);
}

這段代碼中,foo()採用傳值方式來傳遞參數。也就是說i的lvalue並沒有被傳遞到foo()中。相反,在foo()的棧上會產生一個隱藏變數,並將i的rvalue,10,拷貝到其中——這是因為,如果沒有該變數的lvalue,那麼i的rvalue就沒有存放的地方。這樣,無論在foo()中對這個變數做任何修改都不會影響到i。如果要將foo()中i的修改反映到main()中,那就要採用傳引用方式:

int foo(int *i);

int main()
{
    int i = 10;
    return foo(&i);
}

此時,&i表示的是傳遞i的lvalue。因此就不需要建立一個變數來存放該i的rvalue,相當於foo()直接存取main()中的i變數。這樣就能夠通過foo()來修改i的rvalue(參考圖1)。

那麼,如果我要修改例2中p的rvalue——使指標指向另一塊記憶體——也是同樣的道理:

int foo(int & *i);
// Or: int foo(int **i);
// But in c++ we prefer the first one.

int main()
{
    int *p = NULL;
    p = new int(10);
    return foo(p);

    delete p;
}

此時根據foo()的signature,p的引用被傳遞。也就是說,p的lvalue被傳遞進去,那麼修改p的rvalue時就能使p指向另一塊記憶體(參考圖2)。

不光有些變數同時具有lvalue和rvalue,運算式也可能同時具有lvalue和rvalue。在傳遞參數時需要顯式指定使用lvalue或rvalue,除此之外,要判斷使用的是運算式的lvalue還是rvalue,需要根據context來判定。參考“數群組類型、函數類型到左值和右值的轉換”,在這裡有些爭論,不過現在完全同意這篇文章關於l/rvalue的觀點了。

木桶
對於運算式的lvalue來說,它的size是固定的——機器字長。而對於其rvalue來說就不是了。因此不能把兩個不同類型的變數相互賦值。一定要這樣做的話就需要使用類型轉換。這就好比有很多木桶,每個木桶的編號長度都是固定的,但大小不一樣。如果將小木桶裡的水倒入大木桶中自然沒有問題,但要反過來就會有問題,可能會導致資訊丟失。

Copyleft (C) 2007, 2008 raof01. 本文可以用於除商業外的所有用途。此處“用途”包括(但不限於)拷貝/翻譯(部分或全部),不包括根據本文描述來產生代碼及思想。若用於非商業,請保留此權利聲明,並標明文章原始地址和作者資訊;若要用於商業,請與作者聯絡(raof01@gmail.com),否則作者將使用法律來保證權利。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.