簡體   English   中英

復合文字生命周期和if塊

[英]Compound literal lifetime and if blocks

這是一個理論問題,我知道如何明確地做到這一點,但我很好奇並且挖掘了標准,我需要第二對標准律師的眼睛。

讓我們從兩個結構和一個init函數開始:

struct foo {
    int a;
};
struct bar {
    struct foo *f;
};
struct bar *
init_bar(struct foo *f)
{
    struct bar *b = malloc(sizeof *b);
    if (!b)
        return NULL;
    b->f = f;
    return b;
}

我們現在有一個草率的程序員不檢查返回值:

void
x(void)
{
    struct bar *b;

    b = init_bar(&((struct foo){ .a = 42 }));
    b->f->a++;
    free(b);
}

從我對標准的閱讀中,除了可能解除引用NULL指針之外,這里沒有任何錯誤。 通過struct bar的指針修改struct foo應該是合法的,因為發送到init_bar的復合文字的生命周期是包含它的塊,即整個函數x

但現在我們有一個更細心的程序員:

void
y(void)
{
    struct bar *b;

    if ((b = init_bar(&((struct foo){ .a = 42 }))) == NULL)
        err(1, "couldn't allocate b");
    b->f->a++;
    free(b);
}

代碼做同樣的事情,對吧? 所以它也應該工作。 但是仔細閱讀C11標准會讓我相信這會導致不確定的行為。 (重點引用我的)

6.5.2.5復合文字

5復合文字的值是初始化列表初始化的未命名對象的值。 如果復合文字出現在函數體外,則該對象具有靜態存儲持續時間; 否則, 它具有與封閉塊相關的自動存儲持續時間

6.8.4選擇陳述

3 選擇語句是一個塊,其范圍是其封閉塊范圍的嚴格子集。 每個關聯的子語句也是一個塊,其范圍是選擇語句范圍的嚴格子集。

我看對了嗎? if是塊的事實是否意味着復合文字的生命周期只是if語句?

(如果有人想知道這個人為的例子來自哪里,在真正的代碼中, init_bar實際上是pthread_create並且在函數返回之前連接線程,但我不想通過涉及線程來init_bar水域)。

您引用的標准的第二部分(6.8.4選擇聲明)說明了這一點。 在代碼中:

{//scope 1

    if( ... )//scope 2
    {

    }//end scope 2

}//end scope 1

范圍2完全在范圍1內。請注意,在這種情況下, 選擇語句是整個if語句,而不僅僅是括號:

if( ... ){ ... }

在該語句中定義的任何內容都在范圍2中。因此,如第三個示例所示,復合文字的生命周期(在范圍2中聲明)在結束時以括號( 結束范圍2結束 ,因此該示例將導致如果函數返回非NULL,則為未定義的行為(如果err()未終止程序,則為NULL)。

(注意我在if語句中使用了括號,即使第三個示例不使用它們。示例的那部分等同於此( 6.8.2復合語句 ):

if ((b = init_bar(&((struct foo){ .a = 42 }))) == NULL)
{
    err(1, "couldn't allocate b");
}

暫無
暫無

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

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