复合文字生命周期和if块

时间:2016-01-19 15:27:10

标签: c

这是一个理论问题,我知道如何明确地做到这一点,但我很好奇并且深入了解标准,我需要第二对标准律师眼睛。

让我们从两个结构和一个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 foo中的指针修改struct bar应该是合法的,因为发送到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并且在函数返回之前连接了线程,但我不想让这个问题变得混乱涉及线程的水域。

1 个答案:

答案 0 :(得分:5)

您引用的标准的第二部分(6.8.4选择声明)说明了这一点。在代码中:

{//scope 1

    if( ... )//scope 2
    {

    }//end scope 2

}//end scope 1

范围2完全在范围1内。请注意,在这种情况下,选择语句是整个if语句,而不仅仅是括号:

if( ... ){ ... }

该语句中定义的任何内容都在范围2中。因此,如第三个示例所示,复合文字的生命周期(在范围2中声明)在结束时结束,如果括号(结束范围2 < / em>),如果函数返回非NULL,则该示例将导致未定义的行为(如果err()未终止程序,则该示例将为NULL)。

(请注意,我在if语句中使用了括号,即使第三个示例不使用它们。该示例的那部分等同于此( 6.8.2复合语句):< / p>

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