迴圈內部區域性變數與呼叫棧

2021-09-09 03:09:30 字數 1548 閱讀 6885

正如其他部落格所提到的,區域性變數的生命週期是在乙個大括號內,即乙個所處塊結束。

區域性變數和全域性變數的區別,區域性變數的生命週期是從建立開始到所處的塊結束就被**,而全域性變數的生命週期是從建立開始到程式結束。

正如上面所說,區域性變數是直到所處的塊結束才從呼叫棧中把它**。先看下面的**。

for(int i = 0;i<10;i++)

上面**中的的整型變數i知道for迴圈結束之後才被呼叫棧**。它經歷了10次for的運算,知道i=10的時候才退出迴圈,i被呼叫棧銷毀。而j在每一次迴圈都完成一次入棧出棧的操作。

那麼呼叫棧是什麼,它又是如何怎麼運作的呢?

呼叫棧(call stack,英文直接簡稱為「棧」(the stack))最經常被用於存放子程式的返回位址。在呼叫任何子程式時,主程式都必須暫存子程式執行完畢後應該返回到的位址。因此,如果被呼叫的子程式還要呼叫其他的子程式,其自身的返回位址就必須存入呼叫棧,在其自身執行完畢後再行取回。在遞迴程式中,每一層次遞迴都必須在呼叫棧上增加一條位址,因此如果程式出現無限遞迴(或僅僅是過多的遞迴層次),呼叫棧就會產生棧溢位。

呼叫棧的主要功能是存放返回位址。除此之外,呼叫棧還用於存放:

本地變數:子程式的變數可以存入呼叫棧,這樣可以達到不同子程式間變數分離開的作用。

引數傳遞:如果暫存器不足以容納子程式的引數,可以在呼叫棧上存入引數。

環境傳遞:有些語言(如pascal與ada)支援「多層子程式」,即子程式中可以利用主程式的本地變數。這些變數可以通過呼叫棧傳入子程式。

光是了解呼叫棧還不足以理解迴圈內部定義的變數為什麼只有一次迴圈的生命週期。

簡單的來說,就是先把for轉化為while

// for

for (init; test; update)

body

// while version

init;

while (test)

然後以乙個do-while的**為例子來看它的彙編。

// do while 的 c 語言**

long pcount_do

(unsigned long x)

while

(x);

return result;

}

這個函式計算引數 x 中有多少位是 1,翻譯成彙編如下:

movl    $0, %eax    # result = 0

.l2: # loop:

movq %rdi, %rdx

andl $1, %edx # t = x & 0x1

addq %rdx, %rax # result += t

shrq %rdi # x >>= 1

jne .l2 # if (x) goto loop

rep; ret

既然臨時變數會在每一次迴圈**,那為什麼有的時候還能得到正確的值呢?這是以前第二次迴圈為變數分配的位址與原來的位址相同,將變數記憶體釋放時也沒進行記憶體擦除操作,故列印結果為第一次所賦的值。

方法內部多執行緒呼叫區域性變數問題

問題場景 方法內部多執行緒呼叫內部區域性變數集合,併發寫入資料庫,集合執行緒間隔離 執行緒呼叫完畢就需要清空集合 資料不重複寫入問題 核心 片段 class threadsync implements runnable override public void run esrestclient.ge...

內部類,介面,區域性變數

1 介面方法不能包含有方法體,介面方法都是抽象方法 abstract 2 介面方法預設都使用abstract進行修飾,可寫可不寫 自動型別轉換 向上轉型,向下轉型 在內部類中,如果有變數與外部類的變數名稱相同,優先使用內部類的變數 內部類可以直接在外部類中使用,用於完成特定的功能 靜態內部類是外部類...

成員變數與區域性變數

成員變數 作為類的成員而存在,直接存在於類中。所有類的成員變 量可以通過this來引用。區域性變數 作為方法或語句塊的成員而存在,存在於方法的引數列表和方法定義中。1.成員變數可以被 public,protect,private,static等修飾符修飾,而 區域性變數不能被控制修飾符及 stati...