从函数和未定义的行为返回本地部分初始化的结构

250*_*501 18 c struct undefined-behavior language-lawyer c11

(通过部分初始化,我的意思是定义为未初始化,其中一个成员设置为某个有效值,但不是全部.并且本地我的意思是使用自动存储持续时间定义.这个问题只讨论那些.)

使用可以使用register定义的自动未初始化变量,因为rvalue是未定义的行为.可以使用寄存器存储类说明符定义结构.

6.3.2.1

  1. 如果左值指定了一个自动存储持续时间的对象,该对象可以使用寄存器存储类声明(从未使用其地址),并且该对象未初始化(未使用初始化程序声明,并且在使用之前未对其进行任何赋值) ),行为未定义.

请注意,它具体说明并且没有对其进行任何分配.

另外我们知道结构不能是陷阱值:

6.2.6.1.

  1. 结构或联合对象的值永远不是陷阱表示,即使结构或联合对象的成员的值可能是陷阱表示

因此,返回未初始化的结构显然是未定义的行为.

声明:定义了返回一个未初始化的结构,该结构的一个成员被赋予了有效值.

更容易理解的示例:

struct test
{
    int a;
    int b;
};

struct test Get( void )
{
    struct test g;
    g.a = 123;
    return g;
}

{
    struct test t = Get();
}
Run Code Online (Sandbox Code Playgroud)

我碰巧专注于回归,但我相信这也适用于简单的任务,没有任何区别.

我的陈述是否正确?

ric*_*ici 10

除了从函数返回值的详细信息之外,这正是Clive Feather在2000年提交的缺陷报告222的主题,并且该DR的解决方案似乎非常清楚地回答了这个问题:返回部分未初始化struct的很好-defined(尽管可能不使用未初始化成员的值.)

DR的决议澄清说struct,union对象没有陷阱表示(已明确添加到§6.2.6.1/ 6).因此,成员复制不能用于个别成员可能陷阱的体系结构.虽然,大概是为了简约,但没有在标准中添加明确的声明,脚注42(现在的脚注51),前面提到过逐个成员复制的可能性被一个更弱的声明所取代,表明填充比特不需要被复制.

第14 届WG14会议(多伦多,2000年10月)的会议记录明确(重点补充):

DR222 - 部分初始化结构

该DR询问的问题struct是,当赋值的来源是a时struct,赋值是否被很好地定义,其中一些成员没有被赋予值. 由于共同使用,包括标准指定的结构,人们一致认为应该明确定义struct tm.还有一种共识是,如果对某些成员的未初始化(因此可能具有陷阱价值)进行明确界定,则要求至少有一名成员获得适当的价值几乎没有价值.
因此,正在消除a structunion整个值可能具有陷阱值的概念.

值得注意的是,在上述会议记录中,委员会认为甚至没有必要为其中的一个成员struct提供价值.但是,在某些情况下,该要求后来得到了恢复,解决了DR338(见下文).

综上所述:

  • 如果自动聚合对象至少已部分初始化或者其地址已被采用(从而使其不适用于register符合§6.3.2.1/ 2 的声明),则该对象的左值到右值转换很好 -定义.

  • 可以在从函数返回之后将这样的对象分配给相同类型的另一个聚合对象,而不调用未定义的行为.

  • 读取副本中未初始化的成员要么是未定义的要么是不确定的,具体取决于陷阱表示是否可行.(例如,通过指向无符号窄字符类型的指针读取不能捕获.)但是如果您在读取它之前编写成员,那么就没问题了.

我不相信赋值unionstruct对象之间有任何理论上的区别.显然unions不能被成员成员复制(甚至意味着什么),并且一些非活动成员碰巧有陷阱表示的事实是无关紧要的,即使该成员没有被任何其他元素别名化.没有明显的理由说明为什么struct应该有任何不同.

最后,关于§6.3.2.1/ 2中的例外情况:这是因为DR 338的解决方案而增加的.该DR的要点是某些硬件(IA64)可以捕获在寄存器中使用未初始化的值.C99不允许对无符号字符进行陷阱表示.因此,在这样的硬件上,可能无法在寄存器中维护自动变量而不"不必要地"初始化寄存器.

分辨率为DR 338特别标记为不确定的行为使用自动变量初始化值可能令人信服地存储在寄存器(即,那些地址从来没有被采取,仿佛宣告register),从而允许编译器,以保持自动unsigned char在寄存器而不用担心该寄存器的先前内容.

作为DR 338的副作用,似乎完全未初始化的自动structs(其地址从未被采用)不能进行左值到右值的转换.我不知道在DR 338的决议中是否完全考虑了这种副作用,但它不适用于部分初始化的情况struct,如本问题所述.