最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

從Go匯編角度解讀for循環(huán)的問題

 更新時間:2020年02月22日 20:02:44   作者:西山居  
Go常用的遍歷方式有兩種:for和for-range。這篇文章主要介紹了從Go匯編角度解讀for循環(huán)的兩個疑點,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下

Go常用的遍歷方式有兩種:for和for-range。實際上,for-range也只是for的語法糖,本文試圖從匯編代碼入手解釋for循環(huán)是如何工作的。

問題

首先來看看幾個令人迷惑的地方。

問題1:遍歷過程中取值

func main() {
 arr := [5]int{1, 2, 3, 4, 5}
 for _, v := range arr {
  println(&v)
 }
}

上面這段代碼里,會打印出什么?

問題2:遍歷過程中修改

arr := []int{1, 2, 3, 4, 5}
for v := range arr {
 arr = append(arr, v)
}

上面這段代碼里,遍歷前后arr有哪些變化?

窺探虛實

對于問題1,我們期待會打印出5個不同的地址,實際上最終打印出來的都是同一個地址,我們可以猜測v在循環(huán)過程中只聲明了一次。看看問題1的匯編代碼:

0x0028 00040 (main.go:4)  MOVQ ""..stmp_0(SB), AX
0x002f 00047 (main.go:4)  MOVQ AX, "".arr+24(SP)
0x0034 00052 (main.go:4)  MOVUPS ""..stmp_0+8(SB), X0
0x003b 00059 (main.go:4)  MOVUPS X0, "".arr+32(SP)
0x0040 00064 (main.go:4)  MOVUPS ""..stmp_0+24(SB), X0
0x0047 00071 (main.go:4)  MOVUPS X0, "".arr+48(SP)
0x004c 00076 (main.go:5)  MOVQ "".arr+24(SP), AX
0x0051 00081 (main.go:5)  MOVQ AX, ""..autotmp_2+64(SP)
0x0056 00086 (main.go:5)  MOVUPS "".arr+32(SP), X0
0x005b 00091 (main.go:5)  MOVUPS X0, ""..autotmp_2+72(SP)
0x0060 00096 (main.go:5)  MOVUPS "".arr+48(SP), X0
0x0065 00101 (main.go:5)  MOVUPS X0, ""..autotmp_2+88(SP)
0x006a 00106 (main.go:5)  XORL AX, AX
0x006c 00108 (main.go:5)  JMP  162
0x006e 00110 (main.go:5)  MOVQ AX, ""..autotmp_7+16(SP)
0x0073 00115 (main.go:5)  MOVQ ""..autotmp_2+64(SP)(AX*8), CX
0x0078 00120 (main.go:5)  MOVQ CX, "".v+8(SP)
0x007d 00125 (main.go:6)  CALL runtime.printlock(SB)
0x0082 00130 (main.go:6)  LEAQ "".v+8(SP), AX
0x0087 00135 (main.go:6)  MOVQ AX, (SP)
0x008b 00139 (main.go:6)  CALL runtime.printpointer(SB)
0x0090 00144 (main.go:6)  CALL runtime.printnl(SB)
0x0095 00149 (main.go:6)  CALL runtime.printunlock(SB)
0x009a 00154 (main.go:5)  MOVQ ""..autotmp_7+16(SP), AX
0x009f 00159 (main.go:5)  INCQ AX
0x00a2 00162 (main.go:5)  CMPQ AX, $5
0x00a6 00166 (main.go:5)  JLT  110

00040行:MOVQ ""..stmp_0(SB), AX將stmp_0變量里的內(nèi)容放到AX寄存器里,stmp_0實際上就是arr數(shù)組,在生成的匯編代碼里:

""..stmp_0 SRODATA size=40
  0x0000 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00
  0x0010 03 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
  0x0020 05 00 00 00 00 00 00 00

由此可以看到stmp_0正是arr數(shù)組。

00106行:XORL AX AX是初始化AX寄存器,AX寄存器里包含當(dāng)前循環(huán)位置。 00108行:JMP 162表示跳轉(zhuǎn)到00162行。 00162行:CMPQ AX $5比較寄存器AX和5,偽代碼:i < 5,如果滿足條件,則跳轉(zhuǎn)到00110行。

00110行00159行為循環(huán)體代碼,注意到00159行INCQ AX, 意即AX寄存器值自增,到這里我們可以大致分析出來for-range在匯編層面的偽代碼:

for i := 0; i < 5; i++ {
}

這也就驗證了上面說的for-range只是普通for的語法糖。

00110到00120行是循環(huán)體代碼的前半部分。從Go 匯編文檔上看:SP寄存器指向當(dāng)前棧幀的局部變量的開始位置,也就是說局部變量放在了SP寄存器的棧幀里。

00115行:MOVQ ""..autotmp_2+64(SP)(AX*8), CX,autotmp_*是為臨時變量自動生成的名字,這行匯編做的事情是將某個v值(注意,是值)放在CX寄存器里。

00120行:MOVQ CX, "".v+8(SP)將CX寄存器里的內(nèi)容放在SP寄存器指向的位置,00125行代碼是一個隔斷,00125之后的代碼與println有關(guān)。重點在這行代碼,每次循環(huán)都會將值放在"".v+8(SP)這個位置,在這個循環(huán)體代碼里,我們并沒有看到其他的臨時變量聲明,到這里,我們可以總結(jié)出:"".v+8(SP)這個位置就是變量v在棧幀中的位置,由于位置一直沒有發(fā)生變化,在進(jìn)行&v操作時取到的會是同一個地址。

對于問題1,根據(jù)匯編代碼的分析,我們得出結(jié)論:v在循環(huán)過程中只會聲明一次,每次循環(huán)只是將v值替換,并未重新聲明臨時變量,這樣解釋了問題1代碼的輸出結(jié)果。

再回到問題2,我們期待循環(huán)永遠(yuǎn)不會停下來,但實際上循環(huán)5次之后停了下來。我們有理由猜測:循環(huán)體中的arr與arr = append(arr, v)中的并非同一個。

由于兩段代碼的匯編代碼差不多,這里仍以上面的匯編代碼來分析。00106行是初始AX寄存器,也是循環(huán)的開始,所以我們關(guān)注00106行之前的代碼。

根據(jù)上面的分析,在00040行已經(jīng)將數(shù)組內(nèi)容放到了AX寄存器里,00081行到00101行,將數(shù)組拷貝到autotmp_2變量內(nèi),由SP所指向的棧頂。

在讀這段代碼的匯編時,發(fā)現(xiàn)編譯器針對數(shù)組內(nèi)容做了一個小優(yōu)化,當(dāng)數(shù)組長度小于5時候,編譯器會認(rèn)為這個數(shù)組只是臨時變量,會直接做棧上賦值,直接將數(shù)組內(nèi)容放到autotmp_2變量中(棧上),省略了從數(shù)據(jù)只讀區(qū)到AX的過程(即00040行),數(shù)組長度小于5時,匯編代碼如下:

0x0024 00036 (main.go:5) MOVQ $1, ""..autotmp_2+24(SP)
0x002d 00045 (main.go:5) MOVQ $2, ""..autotmp_2+32(SP)
0x0036 00054 (main.go:5) MOVQ $3, ""..autotmp_2+40(SP)
0x003f 00063 (main.go:5) XORL AX, AX

分析到這里,我們可以得到一段表示for循環(huán)的偽代碼:

temp := {1, 2, 3, 4, 5}
for i := 0; i < 5; i++ {
 v := temp[i]
}

由此我們可以得到結(jié)論:for-range時拷貝了被訪問的列表(array、slice、hashmap等)。問題2所帶的思考:當(dāng)數(shù)組比較大時,for-range拷貝數(shù)組的開銷也會比較大,在實際應(yīng)用中應(yīng)當(dāng)避免這個開銷。

總結(jié)

從上面的匯編代碼分析過來看,總結(jié)兩點:

1. 循環(huán)過程中位置變量,只會聲明一次,也就是說每次循環(huán)位置變量的地址都是相同的。 2. for-range時拷貝了被訪問的列表(array、slice、hashmap等)。

延申閱讀

A Quick Guide to Go's Assembler

到此這篇關(guān)于從Go匯編角度解讀for循環(huán)的文章就介紹到這了,更多相關(guān)匯編for循環(huán)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文掌握匯編語言 halt 命令

    一文掌握匯編語言 halt 命令

    匯編 halt 命令,是一條重復(fù)執(zhí)行指定標(biāo)號的循環(huán)命令。處理器暫停,直到出現(xiàn)中斷或復(fù)位信號才繼續(xù),這篇文章主要介紹了匯編語言 halt 命令,需要的朋友可以參考下
    2023-01-01
  • 詳解匯編語言MOV指令

    詳解匯編語言MOV指令

    在匯編語言中,MOV指令是數(shù)據(jù)傳送指令,也是最基本的編程指令,這篇文章主要介紹了匯編語言MOV指令,需要的朋友可以參考下
    2020-01-01
  • 匯編語言AAD,DAA,DAS用法解析

    匯編語言AAD,DAA,DAS用法解析

    這篇文章主要介紹了匯編語言AAD,DAA,DAS用法解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01
  • UEFI開發(fā)實戰(zhàn)用戶交互界面基礎(chǔ)說明

    UEFI開發(fā)實戰(zhàn)用戶交互界面基礎(chǔ)說明

    這篇文章主要為大家介紹了UEFI開發(fā)實戰(zhàn)用戶交互界面的基礎(chǔ)說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • libAccessibility通知Crash排查記錄分析

    libAccessibility通知Crash排查記錄分析

    這篇文章主要為大家介紹了libAccessibility通知Crash排查記錄分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • 匯編語言實現(xiàn)打印楊輝三角

    匯編語言實現(xiàn)打印楊輝三角

    這篇文章主要介紹了匯編語言實現(xiàn)打印楊輝三角,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • 匯編語言乘指令 MUL、IMUL的具體使用

    匯編語言乘指令 MUL、IMUL的具體使用

    這篇文章主要介紹了匯編語言乘指令 MUL、IMUL的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • 匯編語言MUL指令無符號數(shù)乘法的使用

    匯編語言MUL指令無符號數(shù)乘法的使用

    這篇文章主要介紹了匯編語言MUL指令無符號數(shù)乘法的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • C 表達(dá)式中的匯編指令

    C 表達(dá)式中的匯編指令

    這篇文章主要介紹了C 表達(dá)式中的匯編指令,需要的朋友可以參考下
    2020-01-01
  • 淺析ARMv8匯編指令adrp和adr

    淺析ARMv8匯編指令adrp和adr

    這篇文章給大家介紹ARMv8匯編指令adrp和adr的相關(guān)知識,暫時不介紹alpha生成的指令,因此先來主要分析一下,arm架構(gòu)之所以少生成匯編指令的原因——adrp指令,感興趣的朋友跟隨小編一起看看吧
    2021-12-12

最新評論

海淀区| 仙桃市| 大埔区| 汉川市| 安远县| 东乡族自治县| 平舆县| 阳原县| 大竹县| 台中县| 肥西县| 右玉县| 禹城市| 镇雄县| 五大连池市| 那曲县| 遵化市| 宁海县| 乌鲁木齐市| 高要市| 高平市| 延寿县| 石楼县| 西峡县| 上高县| 团风县| 东丽区| 阜阳市| 张掖市| 泰顺县| 连江县| 五原县| 开鲁县| 同江市| 克拉玛依市| 马山县| 甘孜县| 神农架林区| 贡觉县| 贞丰县| 抚松县|