簡體   English   中英

alloca的函數范圍中的goto是否有效?

[英]Is a goto in alloca's function scope valid?

C標准禁止轉入存在VLA的功能范圍。

VLA和對alloca函數的調用應該在低級別上具有相同的結果。

(我可能是錯的,因為我只是一個C,而不是一個低級程序員,但在我的想象中,似乎很機智)

那么下面的代碼片段也會是未定義的行為嗎?

int main()
{
    char *p;

    goto label1;

    {
        p = _alloca(1);
label1:
        p = NULL;
    }
}

當然我不能參考p ,但關於這種行為是什么?

實際上,規則6.8.6.1規定:

  A goto statement is not allowed to jump past any declarations of objects 
  with variably modified types.

在您的代碼中,不存在具有可變修改類型的對象。 alloca 聲明一個對象(即編譯器必須關心的)。 因此,沒有什么比alloca的范圍alloca ,並且沒有理由在規則6.8.6.1的意義上存在未定義的行為。

編輯

稍微詳細說明答案:VLA情況下行為的“不確定性”是由於承諾聲明對象在其范圍內(在語言級別)“已知”。 通常,聲明為代碼執行設置上下文。 它不需要在運行時執行。 但是,在VLA的情況下情況並非如此:這里的承諾部分在運行時實現,打破了C的靜態聲明方法。 為了避免導致動態類型系統的進一步沖突,規則6.8.6.1避免了這種沖突。

相反,在語言層面, alloca只是一個函數; 它的召喚不構成任何范圍。 它只是對它的運行時行為的承諾,以防它被調用。 如果它沒有被調用,我們不會“期望”任何函數。 因此,它的純粹存在不會引起任何沖突:兩種情況(繞過或不繞過)都有明確定義的語義。

VLA和對alloca函數的調用應該在低級別上具有相同的結果。

仍然存在一些差異。 當聲明的范圍結束並且函數返回時丟棄由alloca分配的內存對象時,將丟棄VLA對象。

這有所不同,因為c99,6.8.6.1p1中的要求( “一個goto語句不應該從具有可變修改類型的標識符范圍之外跳轉到該標識符的范圍內” )與運行時分配/有關。具有可變修改類型的對象的解除分配。 這里執行goto后不執行alloca語句,所以我不認為goto調用會調用未定義的行為。

C標准對alloca()的行為沒什么好說的。 一些編譯器以非常可預測的方式使用堆棧,並使用大量冗余的幀指針訪問自動變量。 在這樣的編譯器上,可以通過簡單地從堆棧指針中減去一個值來保留堆棧上的空間,而編譯器不必知道或關心有問題的預留。 但是,如果編譯器以應用程序不期望的方式使用堆棧,則此類代碼將會嚴重破壞。

我不認為這樣的事情:

  int *p = 0;
  if (!foo(1,2,3))
    goto skip_alloca;
  p=alloca(46);
skip_alloca:
  bar(4,5,6);
  ...

比以下更容易危險:

  int *p = 0;
  if (foo(1,2,3))
    p=alloca(46);
  bar(4,5,6);
  ...

如果在執行alloca()時函數調用中堆棧上沒有殘留,則任一操作都可能是安全的。 如果在alloca時堆棧上有殘留(例如因為編譯器選擇在調用bar之后推遲清除foo的參數),這會使alloca()行為異常。 使用代碼的goto版本實際上可能比使用if的版本更安全,因為編譯器更難以識別將清理推遲到foo可能是有利的。

暫無
暫無

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

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