英文:
Does reading to another variant member of a union that has the same type as the active variant cause UB?
问题
union A {
int a;
int b;
};
int main() {
A u = {.a = 0};
int r = u.b; // #1 这是否属于未定义行为?
}
[class.union] 规定:
> 在联合体中,如果非静态数据成员的名称引用的是已经开始但尚未结束生命周期的对象,则该成员是活跃的。在任何时候,联合体对象的一个非静态数据成员最多只能是活跃的,也就是说,在任何时候,最多只能在联合体中存储一个非静态数据成员的值。
在这个例子中,只有 A::a
是活跃的,然后[basic.life] 第7段规定:
> 如果程序使用 glvalue 来访问对象,或者
#1
试图访问尚未开始生命周期的对象。这种访问是否会导致未定义行为?如果是的话,这个要求是否太严格了?
另外,C 标准是否在这个例子中施加了相同的要求?还是说,C 在这种情况下有更宽松的要求?
更新
在C标准中,我找到了一个注释,其中提到:
> 如果用于读取联合体对象的内容的成员与最后用于在对象中存储值的成员不同,则该值的对象表示的适当部分将被重新解释为新类型的对象表示,如6.2.6中所述(有时称为类型切换过程)。这可能是非值表示。
这意味着在C中是允许的。然而,https://eel.is/c++draft/diff.iso
> 子句 [diff.iso] 列出了C++和ISO C之间的差异,除了上面列出的差异外,还包括本文各章的差异。
并没有指出差异。
英文:
union A{
int a;
int b;
};
int main(){
A u = {.a = 0};
int r = u.b; // #1 Is this UB?
}
[class.union] says
> In a union, a non-static data member is active if its name refers to an object whose lifetime has begun and has not ended ([basic.life]).
At most one of the non-static data members of an object of union type can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time.
In this example, only A::a
is active, then [basic.life] p7 says
> The program has undefined behavior if:
>> - the glvalue is used to access the object, or
#1
tries to access the object whose lifetime has not begun. Does this access cause UB, if it is, is this requirement too restrictive?
BTW, Does the C standard impose the same requirement in this example? Or, Does C have a looser requirement in this case?
Update
In C standard, I find a note, which says
> If the member used to read the contents of a union object is not the same as the member last used to store a value in the
object the appropriate part of the object representation of the value is reinterpreted as an object representation in the new
type as described in 6.2.6 (a process sometimes called type punning). This might be a non-value representation.
This means it is permitted in C. However, https://eel.is/c++draft/diff.iso
> Subclause [diff.iso] lists the differences between C++ and ISO C, in addition to those listed above, by the chapters of this document.
does not point out the difference.
答案1
得分: 5
我认为在C++中,根据问题本身中的第一个标准引用,这是未定义行为:对于数据成员类型相同的情况,没有特殊的例外情况。
而且,主要的编译器似乎也支持这种解释,在常量表达式中禁止这样的代码:
union A{
int a;
int b;
};
constexpr int f() {
A u = {.a = 0};
return u.b;
}
constexpr int x = f();
在线演示:https://gcc.godbolt.org/z/We4zYzdaa
Clang的错误:
尝试在常量表达式中读取联合体的成员'b',而成员'a'处于活动状态,不允许
GCC的错误:
在常量表达式中访问'A::b'成员,而不是已初始化的'A::a'成员
MSVC的错误:
访问联合体的非活动成员导致失败
(请注意,这是上述代码的翻译,不包括代码本身。)
英文:
I think in C++ this is undefined behavior per the first standard quotation in the question itself: there is no exception there for the case of same types of data members.
And major compilers seem to agree with this reading, disallowing such code in constant expressions:
union A{
int a;
int b;
};
constexpr int f() {
A u = {.a = 0};
return u.b;
}
constexpr int x = f();
Online demo: https://gcc.godbolt.org/z/We4zYzdaa
Clang's error:
read of member 'b' of union with active member 'a' is not allowed in a constant expression
GCC's error:
accessing 'A::b' member instead of initialized 'A::a' member in constant expression
MSVC's error:
failure was caused by accessing a non-active member of a union
答案2
得分: 3
> Does reading to another variant member of a union that has the same type as the active variant cause UB?
规则很清楚。一个成员是活动的。读取非活动成员会导致未定义行为。
> Does this access cause UB
是的。
> , if it is, is this requirement too restrictive?
不清楚。主观看法:对我来说没问题。这是可以接受的。我认为在联合体中有两个相同类型的成员,然后访问它们之一没有什么意义。
> Does the C standard impose the same requirement in this example?
不。这是C和C++不同的例子之一。
> Does C have a looser requirement in this case?
是的。在C中,你可以读取联合体中的任何成员。要求的是评估的值不会是 trap representation。
相关链接:https://stackoverflow.com/questions/25664848/unions-and-type-punning
英文:
> Does reading to another variant member of a union that has the same type as the active variant cause UB?
The rule is clear. One member is active. Reading inactive is UB.
> Does this access cause UB
Yes.
> , if it is, is this requirement too restrictive?
No idea. Subjective: Not for me. It is fine. I see no value in having two members of the same type in a union and then accessing them one or the other.
> Does the C standard impose the same requirement in this example?
No. One of examples that C and C++ are different.
> Does C have a looser requirement in this case?
Yes. In C, you can read any member from a union you want to. The requirement is that the assessed value will not be a trap representation.
Related: https://stackoverflow.com/questions/25664848/unions-and-type-punning
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论