乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      阿里云二面:引用和指針有什么區(qū)別?

       伊伊爸 2022-05-24 發(fā)布于湖北

      大家好。

      上周有個(gè)同學(xué)說面阿里云存儲(chǔ)被問到了引用和指針的區(qū)別,并且給我發(fā)了一些百度上搜到的標(biāo)準(zhǔn)回答。

      所以在這分享一下剛學(xué) C++ 時(shí)寫的一篇博客,是關(guān)于指針和引用的區(qū)別的,基本沒有做修改,講解可能會(huì)比較粗略,需要有一點(diǎn)點(diǎn)匯編的知識(shí)。

      引用和指針有什么區(qū)別呢?

      相信大多數(shù)學(xué)過 C++ 的都能回答上幾點(diǎn):

      • 指針是所指內(nèi)存的地址
      • 引用是別名
      • 引用必須初始化,并且初始化后不能重新引用其它變量

      但是引用是別名這是 C++ 語法規(guī)定的語義。

      那么到底引用在匯編層面和指針有什么區(qū)別呢?

      沒區(qū)別。

      是的,這是我當(dāng)時(shí)自己反匯編觀察后得出的結(jié)論,引用會(huì)被 C++ 編譯器當(dāng)做 const 指針來進(jìn)行操作。

      我們來看個(gè)例子:

      匯編揭開引用面紗

      先分別用指針和引用來寫個(gè)非常熟悉的函數(shù)swap

      // 指針版
      void swap(int *a, int *b) {
          int temp = *a;
          *a = *b;
          *b = temp;
      }
      // 引用版
      void swap(int &a, int &b) {
          int temp = a;
          a = b;
          b = temp;
      }

      直接 gcc -S 輸出匯編:

      引用版匯編

      __Z4swapRiS_:                           ## @_Z4swapRiS_
      .cfi_startproc
      ## %bb.0:
      pushq %rbp
      .cfi_def_cfa_offset 16
      .cfi_offset %rbp, -16
      movq %rsp, %rbp
      .cfi_def_cfa_register %rbp
      movq %rdi, -8(%rbp) # 傳入的第一個(gè)參數(shù)存放到%rbp-8 (應(yīng)該是采用的寄存器傳參,而不是常見的壓棧)
      movq %rsi, -16(%rbp) # 第二個(gè)參數(shù) 存放到 %rbp-16
      movq -8(%rbp), %rsi # 第一個(gè)參數(shù)賦給 rsi
      movl (%rsi), %eax # 以第一個(gè)參數(shù)為地址取出值賦給eax,取出*a暫存寄存器
      movl %eax, -20(%rbp) # temp = a
      movq -16(%rbp), %rsi # 將第二個(gè)參數(shù)重復(fù)上面的
      movl (%rsi), %eax
      movq -8(%rbp), %rsi
      movl %eax, (%rsi) # a = b
      movl -20(%rbp), %eax # eax = temp
      movq -16(%rbp), %rsi
      movl %eax, (%rsi) # b = temp
      popq %rbp
      retq
      .cfi_endproc
      ## -- End function

      在來一個(gè)函數(shù)調(diào)用引用版本 swap

      void call() {
          int a = 10;
          int b = 3;
          int &ra = a;
          int &rb = b;
          swap(ra, rb);
      }

      對(duì)應(yīng)匯編:

      __Z4callv:                              ## @_Z4callv
      .cfi_startproc
      ## %bb.0:
      pushq %rbp
      .cfi_def_cfa_offset 16
      .cfi_offset %rbp, -16
      movq %rsp, %rbp
      .cfi_def_cfa_register %rbp
      subq $32, %rsp
      leaq -8(%rbp), %rax # rax中是b的地址
      leaq -4(%rbp), %rcx # rcx中是a的地址
      movl $10, -4(%rbp)
      movl $3, -8(%rbp) # 分別初始化a、b
      movq %rcx, -16(%rbp) # 賦給ra引用
      movq %rax, -24(%rbp) # 賦給rc引用
      movq -16(%rbp), %rdi # 寄存器傳參, -16(%rbp)就是rcx中的值也就是a的地址
      movq -24(%rbp), %rsi # 略
      callq __Z4swapRiS_
      addq $32, %rsp
      popq %rbp
      retq

      從上面我們可以看到給引用賦初值,也就是把所引用對(duì)象的地址賦給引用所在內(nèi)存,和指針是一樣的。

      再來看看指針的匯編吧

      指針版匯編

      __Z4swapPiS_: ## @_Z4swapPiS_
      .cfi_startproc
      ## %bb.0:
      pushq %rbp
      .cfi_def_cfa_offset 16
      .cfi_offset %rbp, -16
      movq %rsp, %rbp
      .cfi_def_cfa_register %rbp
      movq %rdi, -8(%rbp)
      movq %rsi, -16(%rbp)
      movq -8(%rbp), %rsi
      movl (%rsi), %eax
      movl %eax, -20(%rbp)
      movq -16(%rbp), %rsi
      movl (%rsi), %eax
      movq -8(%rbp), %rsi
      movl %eax, (%rsi)
      movl -20(%rbp), %eax
      movq -16(%rbp), %rsi
      movl %eax, (%rsi)
      popq %rbp
      retq
      .cfi_endproc
      ## -- End function

      匯編我就不注釋了,真的是完全一樣!并不是我直接復(fù)制的引用匯編而是真的在編譯器實(shí)現(xiàn)上都是相同的方式。

      指針版調(diào)用

      void pointer_call() {
          int a = 10;
          int b = 3;
          int *pa = &a;
          int *pb = &b;
          swap(pa, pb);
      }

      這次我特意改了下函數(shù)名,對(duì)應(yīng)匯編:

      __Z12pointer_callv: ## @_Z12pointer_callv
      .cfi_startproc
      ## %bb.0:
      pushq %rbp
      .cfi_def_cfa_offset 16
      .cfi_offset %rbp, -16
      movq %rsp, %rbp
      .cfi_def_cfa_register %rbp
      subq $32, %rsp
      leaq -8(%rbp), %rax
      leaq -4(%rbp), %rcx
      movl $10, -4(%rbp)
      movl $3, -8(%rbp)
      movq %rcx, -16(%rbp)
      movq %rax, -24(%rbp)
      movq -16(%rbp), %rdi
      movq -24(%rbp), %rsi
      callq __Z4swapPiS_
      addq $32, %rsp
      popq %rbp
      retq

      還是幾乎完全一樣.......也沒再注釋

      簡(jiǎn)單總結(jié)

      1. 引用只是c++語法糖,可以看作編譯器自動(dòng)完成取地址、解引用的常量指針
      2. 引用區(qū)別于指針的特性都是編譯器約束完成的,一旦編譯成匯編就喝指針一樣
      3. 由于引用只是指針包裝了下,所以也存在風(fēng)險(xiǎn),比如如下代碼:
        int *a = new int;
        int &b = *a;
        delete a;
        b = 12;    // 對(duì)已經(jīng)釋放的內(nèi)存解引用
      4. 引用由編譯器保證初始化,使用起來較為方便(如不用檢查空指針等)
      5. 盡量用引用代替指針
      6. 引用沒有頂層 const (引用本身不可變) 即int & const,因?yàn)橐帽旧砭筒豢勺?,所以在加頂?const 也沒有意義;但是可以有底層 const ()即 const int&,這表示引用所引用的對(duì)象本身是常量
      7. 指針既有頂層const(int * const--指針本身不可變),也有底層const(const int *--指針?biāo)赶虻膶?duì)象不可變)
      8. 有指針引用--是引用,綁定到指針, 但是沒有引用指針--這很顯然,因?yàn)楹芏鄷r(shí)候指針存在的意義就是間接改變對(duì)象的值。但是引用本身的值我們上面說過了是所引用對(duì)象的地址,但是引用不能更改所引用的對(duì)象,也就當(dāng)然不能有引用指針了。
      9. 指針和引用的自增(++)和自減含義不同,指針是指針運(yùn)算, 而引用是代表所指向的對(duì)象對(duì)象執(zhí)行++或--


        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多