[英]A question about the differing behaviours of local static variables in C
我一直在探索 C 中 static 變量的行為,使用以下代碼:
#include <stdio.h>
int f(int n)
{
static int r = 10;
if (n <= 0)
return 7;
if (n > 2)
return f(n-1) + r; // Important line
else{
r = 17;
return f(n-1) + n;
}
}
int main(void)
{
int n = 4;
printf("%d\n", f(n));
return 0;
}
現在,如果您注意到代碼中的“重要行”( return f(n-1) + r
),它會首先調用 function f ,這會將static 變量更改為r 。
但是,如果我將該行更改為return r + f(n-1)
,我預計r將存儲在臨時寄存器中,然后才會評估 function f 。 然而,這似乎並沒有發生,因為在這兩種情況下,首先評估 function f 。 我什至檢查了編譯器生成的匯編代碼,在這兩種情況下它首先調用 function。
但是,如果我將行更改為return (r+2) + f(n-1)
,則(r+2)
會先求值並存儲在臨時寄存器中,然后才求值 function f 。
如果我再次更改該行以return f(n-1) + (r+2)
,那么首先評估的是 function f 。
因此,在程序中使用return r + f(n-1)
和return f(n-1) + r
得到完全相同的 output。
但是,使用return (r+2) + f(n-1)
和return f(n-1) + (r+2)
給出不同的輸出。
我不明白為什么 static 變量的行為會出現這種差異。 根據我的理解,作為return r + f(n-1)
顯然應該首先評估r ,但這並沒有發生。 任何人都可以解釋為什么嗎? 為什么這種行為不一致? 如果我使用(r+2)
而不是r
為什么它會改變?
C 將這些決定留給編譯器。
你的期望是沒有根據的。
您談論的是寄存器,但是 C 不需要使用寄存器的機器。
你說的是+
的操作數求值的相對順序,但是 C 對此沒有要求。 編譯器可以按照其選擇的順序自由地評估它們。
差異源於您所做的錯誤假設。 您所有的問題都得到了回答:這取決於編譯器。
但是,如果我將該行更改為返回 r + f(n-1),我預計 r 將存儲在臨時寄存器中,然后才會計算 function f。
不。
首先,變量是否暫存在寄存器中是一個實現細節,只影響優化,不影響程序的結果。 同樣在遞歸的情況下,如果寄存器沒有按照調用約定堆疊,它就不能合理地將變量存儲在寄存器中,否則它會很快用完寄存器。 它怎么知道要使用哪個寄存器,因為無論我們在遞歸中有多深,機器代碼都是相同的。
關於程序行為,那么在這種情況下適用的是操作數的評估順序,在+
的情況下是未指定/未排序的 (C17 6.5/3)。 這意味着您無法知道r
或f(n-1)
是否會首先被評估,編譯器也不需要根據情況對評估進行一致的排序。 當然,不同的編譯器可能會對它們進行不同的排序。
您不應在與 function 調用相同的表達式中使用r
。 如果r
應該在遞歸調用的某個scope內始終保持不變,則需要在輸入function時手動將其存儲在臨時變量中。
值得注意的是,普通循環比遞歸更快,更不容易出錯。 它還將消除對static
變量的需要,因此它是線程安全的,與您當前的代碼不同。 在 C 中實際使用遞歸的情況很少,這不是其中之一。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.