[英]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.