【发布时间】:2019-03-01 05:45:16
【问题描述】:
假设我们有:
char* a;
int i;
许多对 C++ 的介绍(如 this one)表明右值 a+i 和 &a[i] 可以互换。几十年来我天真地相信了这一点,直到最近我偶然发现了以下引用自 [dcl.ref] 的文字 (here):
特别是,空引用不能存在于定义良好的程序中,因为创建此类引用的唯一方法是将其绑定到通过取消引用空指针获得的“对象”,这会导致未定义的行为。
换句话说,将引用对象“绑定”到 null 取消引用会导致未定义的行为。基于context of the above text,可以推断出仅评估 &a[i](在offsetof 宏内)被认为是“绑定”引用。此外,似乎有一个共识,即&a[i] 在a=null 和i=0 的情况下会导致未定义的行为。这种行为不同于a+i(至少in C++, in the a=null, i=0 case)。
这导致了至少 2 个关于 a+i 和 &a[i] 之间差异的问题:
首先,a+i 和 &a[i] 之间的潜在语义差异是什么导致了这种行为差异。是否可以用任何一种一般原则来解释,而不仅仅是“将引用绑定到空解引用对象会导致未定义的行为仅仅因为这是每个人都知道的非常具体的情况”?是不是&a[i] 可能会生成对a[i] 的内存访问?或者规范作者那天对 null 取消引用不满意?还是别的什么?
其次,除了a=null 和i=0 的情况之外,还有其他情况a+i 和&a[i] 的行为不同吗? (可能包含在第一个问题中,具体取决于它的答案。)
【问题讨论】:
-
根据答案here,如果
a=null,a+i是未定义的,尽管你的第四个链接说它是定义如果i=0,嗯 -
@kmdreko。那是个很好的观点。我已经调整了差异描述以关注
a=null、i=0的情况,以确定a+i和&a[i]之间存在a 差异......再次,导致人们想知道如果它们之间有任何其他差异。 -
当
a是空指针时,标准的意图绝不是禁止&*a。这是issue 232的主题。 -
@n.m.非常有趣的是,提议的解决方案只指定了在
a是null或“一个数组的最后一个元素之后”的情况下会发生什么。这些几乎是空左值的两个最有用的例子!但是为什么他们停在那里而不只是让a+i和&a[i]完全等效...? -
更可怕的是,
a[i]和i[a]实际上是可以互换的……因为 C.(试试看。)
标签: c++ language-lawyer pointer-arithmetic