【发布时间】:2021-01-17 18:24:42
【问题描述】:
在本次讨论中,我假设标量对象是整数、浮点数、字符、布尔值和指针之类的东西。非标量对象是由标量类型和递归聚合组成的聚合(结构)。
鉴于此假设,C++ 程序是否曾经从它们的标量组件中区分访问聚合?
举个例子:
struct s { int a; float b; };
void assign1(s& out, s const& in) { out = in; }
void assign2(s& out, s const& in) { out.a = in.a; out.b = in.b; }
显然assign1 和assign2 在实践中是等价的,并且都可以访问int s::a 和float s::b。但是它们中的任何一个是否也在任何意义上都访问了整个聚合?
只有标量对象才被实际访问的解释产生了有趣的结果。
例如,根据我的另一个问题here 的解决方案,形成对对象的引用并不构成访问。鉴于该分辨率,我可以编写如下函数:
void assign3(s& out, s const& in) {
int& a_out = out.a; // no access
int const& a_in = in.a; // no access
a_out = a_in; // access some ints
}
没有“访问”出现,除了第三行,它访问一些整数。 out 和 in 是否实际引用 s 类型的对象是无关紧要的。只有a_out 和a_in 必须实际引用整数。
鉴于这一点,以及对象的地址是其第一个非静态数据成员的地址这一事实,我有权写
int out, const in = 42;
assign3(reinterpret_cast<s&>(out), reinterpret_cast<s const&>(in));
如果所有这些假设都成立,那么 C 和 C++ 在很大程度上只是可移植的汇编语言,而别名规则只是为了帮助编译器正确地从 x87 浮点协处理器中读取寄存器。
当然,假设不成立。我错了。但是为什么我错了?为什么标准文档有这些关于有效类型或动态类型的规则?
考虑到struct a { int a; }; struct b { int b; };,通过b::b undefined 访问a::a 有什么好处,除非在涉及工会的一些有限情况下?
【问题讨论】:
-
这个问题有一个有趣的倒置:语言不会使任何东西未定义。反过来说:最初,什么都没有定义。然后标准定义了一些东西。它有时会强调它遗漏了一些东西,或者明确遗漏了原本会被规则涵盖的东西。
-
您是正确的,该文档没有“取消定义”事物。但是撰写该文档的人通常是有充分理由的。他们认为通过使行为的某些方面“未定义”可以获得一些东西。我想知道为什么。
-
@LanguageLawyer 这个问题是相关的,但它没有解决
object.member是否构成对member或整个object的访问。
标签: c++ language-lawyer strict-aliasing