簡體   English   中英

關於 C 中局部 static 變量不同行為的問題

[英]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)。 這意味着您無法知道rf(n-1)是否會首先被評估,編譯器也不需要根據情況對評估進行一致的排序。 當然,不同的編譯器可能會對它們進行不同的排序。

您不應在與 function 調用相同的表達式中使用r 如果r應該在遞歸調用的某個scope內始終保持不變,則需要在輸入function時手動將其存儲在臨時變量中。

值得注意的是,普通循環比遞歸更快,更不容易出錯。 它還將消除對static變量的需要,因此它是線程安全的,與您當前的代碼不同。 在 C 中實際使用遞歸的情況很少,這不是其中之一。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM