【发布时间】:2013-12-14 01:07:25
【问题描述】:
在 C 和 C++ 中,使用结束指针来编写可以对任意大数组进行操作的函数通常很有用。 C++ 提供了一个std::end 重载以使这更容易。另一方面,在 C 中,我发现像这样定义和使用宏的情况并不少见:
#define ARRAYLEN(array) (sizeof(array)/sizeof(array[0]))
// ...
int a [42];
do_something (a, a + ARRAYLEN (a));
我还看到了一个指针算术技巧,用于让此类函数对单个对象进行操作:
int b;
do_something (&b, &b + 1);
我突然想到可以用数组来做类似的事情,因为它们被 C(而且,我相信,C++)认为是“完整的对象”。给定一个数组,我们可以在它之后立即派生一个指向数组的指针,取消对该指针的引用,并对结果引用的数组使用数组到指针的转换来获得原始数组的结束指针:
#define END(array) (*(&array + 1))
// ...
int a [42];
do_something (a, END (a));
我的问题是:在取消引用指向不存在的数组对象的指针时,这段代码是否表现出未定义的行为?我对 C 和 C++ 的最新版本有什么感兴趣说一下这段代码(不是因为我打算使用它,因为有更好的方法可以达到相同的结果,而是因为这是一个有趣的问题)。
【问题讨论】:
-
我很惊讶这还没有答案,但是经过大量阅读后,我认为共识是指向数组末尾之后的指针是一个无法取消引用的有效指针.引用的 C 标准的常见段落是
6.5.6/8。在 C++ 中它是5.7/5。如果你有兴趣,这里是diff checker link。 -
@remyabel 这似乎表明该代码不合法。出于指针算术的目的,C(不确定 C++)认为完整的对象等同于范围为 1 的数组的唯一元素(在这种情况下,
int[42]类型的数组是数组的唯一元素类型为int[1][42])。6.5.8明确禁止取消引用过去的指针(在评估的上下文中),例如由&array + 1形成的指针,正在被取消引用。 -
@StuartOlsen:但是数组到指针的转换(通常称为衰减)是评估的上下文吗?它不使用对象的值,只使用它的地址。
-
@BenVoigt 我相信评估的上下文规则是指正在评估的间接(即
*ptr出现在sizeof/alignof/_Alignof表达式之外)。 “如果结果指向数组对象的最后一个元素,则它不应用作评估的一元*运算符的操作数” -6.5.6.8, N1570 -
@StuartOlsen:毫无疑问,这些都是未经评估的上下文。但其他人可能是。例如,在 C++ 中,绑定引用不会评估它绑定到的对象。 (注意第 5.3.1 节第 1 段)
标签: c++ c c++11 undefined-behavior c11