C 是否使用未指定所有成员的结构?

C 是否使用未指定所有成员的结构?,c,struct,language-lawyer,undefined-behavior,C,Struct,Language Lawyer,Undefined Behavior,在块范围内考虑此代码: struct foo { unsigned char a; unsigned char b; } x, y; x.a = 0; y = x; C[N1570]6.3.2.1 2表示“如果左值指定了一个自动存储持续时间的对象,该对象本可以用寄存器存储类声明(从未获取其地址),并且该对象未初始化(未用初始值设定项声明,并且在使用前未对其进行赋值),该行为未定义。“ 虽然已为x的成员分配了一个值,但未执行对x的分配,也未获取其地址。因此,似乎6.3.2.12告诉我们y=x中x

在块范围内考虑此代码:

struct foo { unsigned char a; unsigned char b; } x, y;
x.a = 0;
y = x;
C[N1570]6.3.2.1 2表示“如果左值指定了一个自动存储持续时间的对象,该对象本可以用寄存器存储类声明(从未获取其地址),并且该对象未初始化(未用初始值设定项声明,并且在使用前未对其进行赋值),该行为未定义。“

虽然已为
x
的成员分配了一个值,但未执行对
x
的分配,也未获取其地址。因此,似乎6.3.2.12告诉我们
y=x
x
的行为未定义

但是,如果我们给<代码> x < />代码中的每一个成员赋值,考虑到<代码> x <代码>,对于63.2.1 2的目的,似乎是不合理的。

(1) 严格来说,标准中是否有任何内容导致6.3.2.1 2不适用于(未定义)上述规范

(2) 假设我们正在修改标准或确定对6.3.2.1.2的合理修改,是否有理由选择以下其中一项?(a) 6.3.2.1 2不适用于结构。(b) 如果一个结构的至少一个构件已被赋值,则该结构不会因6.3.2.1.2的目的而未初始化。(c) 如果已为结构的所有命名1成员分配了一个值,则在6.3.2.1.2中,该结构不是未初始化的

脚注
1结构可能有未命名的成员,因此并非总是可以为结构的每个成员指定值。(根据6.7.9.9,即使结构已初始化,未命名的成员也具有不确定的值。)

我的观点是,这是未定义的行为,因为标准未明确定义。从4合规性§2(强调我的):

…未定义的行为是另一种行为 在本国际标准中用“未定义行为”或 省略任何明确的行为定义

在多次阅读N1570草稿之后,我找不到任何关于使用部分初始化结构的行为的明确定义。一方面,第6.3.2.1条第2款规定:

…如果 左值指定了一个自动存储持续时间的对象,该对象可以 使用寄存器存储类声明(从未获取其地址),以及该对象 未初始化(未使用初始值设定项声明,且未对其进行赋值) 在使用前执行),行为未定义

所以这里的
x
是自动的,从来没有被初始化过(只有一个成员),令人钦佩的是,它的地址从来没有被取过,所以我们可以认为它是明确的UB

另一方面,6.2.6.1§6规定:

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

正如6.2.6.1§5刚刚定义的陷阱表示:

某些对象表示不需要表示对象类型的值。如果存储 对象的值具有这样的表示形式,并由一个左值表达式读取,该表达式 没有字符类型,行为未定义。如果提出了这样的陈述 通过一个左值表达式修改对象的全部或任何部分的副作用,左值表达式表示
a
成员的0值和
b
成员的未定义值。 没有字符类型,行为未定义。50)调用这样的表示 陷阱表示法

我们可以认为,获取结构的值始终是合法的,因为它不能是陷阱表示

此外,我还不清楚设置结构成员的值是否会使结构处于单位化状态

基于所有这些原因,我认为该标准没有明确界定行为应该是什么,只是出于这个原因,它是未定义的行为



也就是说,我非常确定任何通用编译器都会接受它,并将
y
给出
x
的当前表示形式,这意味着
a
成员的值为0,而
b
成员的值与
x.b
当前表示形式相同

C标准规定结构类型不能有陷阱表示,尽管结构的成员可能有陷阱表示。在涉及部分书面结构的情况下,该担保将是有用的。此外,在编写所有成员之前禁止复制结构,即使是副本接收者永远不会使用的结构,这将要求程序员编写不必要的低效代码,并且没有任何有用的用途。以“优化”的名义强加这样的要求将是彻头彻尾的愚蠢,而且我不知道有任何证据表明该标准的作者有意这么做

不幸的是,标准的作者使用相同的术语来描述两种情况:

  • 有些实现在所有情况下都定义了某些action X的行为,而有些实现仅为某些情况定义它;标准的其他部分在一些选定的情况下定义了操作。作者想说的是,实现的行为不必像在所有情况下定义行为的实现那样,而不会撤销标准中其他地方做出的保证

  • 尽管在某些情况下,标准的其他部分会定义动作X的行为,但在所有此类情况下保证行为可能代价高昂,即使在标准的其他部分会定义它们的情况下,实现也不需要保证它们

  • 在编写标准之前,有些实现会对所有自动变量进行零初始化。因此,这些实现将保证读取未初始化值的行为,