通过下标获取最后一个数组元素的地址:C++ 标准是否合法? [英] Take the address of a one-past-the-end array element via subscript: legal by the C++ Standard or not?

查看:52
本文介绍了通过下标获取最后一个数组元素的地址:C++ 标准是否合法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经看到它多次断言 C++ 标准不允许以下代码:

I have seen it asserted several times now that the following code is not allowed by the C++ Standard:

int array[5];
int *array_begin = &array[0];
int *array_end = &array[5];

&array[5] 在这种情况下是合法的 C++ 代码吗?

Is &array[5] legal C++ code in this context?

如果可能,我想要一个参考标准的答案.

I would like an answer with a reference to the Standard if possible.

了解它是否符合 C 标准也很有趣.如果它不是标准的 C++,为什么决定将它与 array + 5&array[4] + 1 区别对待?

It would also be interesting to know if it meets the C standard. And if it isn't standard C++, why was the decision made to treat it differently from array + 5 or &array[4] + 1?

推荐答案

您的示例是合法的,但只是因为您实际上并未使用越界指针.

Your example is legal, but only because you're not actually using an out of bounds pointer.

让我们先处理越界指针(因为这就是我最初解释您的问题的方式,然后我注意到该示例使用了一个越界指针):

Let's deal with out of bounds pointers first (because that's how I originally interpreted your question, before I noticed that the example uses a one-past-the-end pointer instead):

一般来说,您甚至不允许创建越界指针.一个指针必须指向数组中的一个元素,或者末尾的一个元素.无处可去.

In general, you're not even allowed to create an out-of-bounds pointer. A pointer must point to an element within the array, or one past the end. Nowhere else.

指针甚至不允许存在,这意味着您显然也不允许取消引用它.

The pointer is not even allowed to exist, which means you're obviously not allowed to dereference it either.

以下是标准对该主题的说明:

Here's what the standard has to say on the subject:

5.7:5:

当一个表达式具有整数类型被添加到或减去指针,结果的类型为指针操作数.如果指针操作数指向一个元素数组对象,且数组很大足够了,结果指向一个元素从原始偏移元素使得差异结果的下标和原始数组元素等于积分表达式.换句话说,如果表达式 P 指向第 i 个数组对象的元素,表达式 (P)+N(相当于,N+(P)) 和 (P)-N(其中 N 具有值 n) 分别指向的第 i+n 个和第 i-n 个元素数组对象,前提是它们存在.此外,如果表达式 P 指向到数组的最后一个元素对象,表达式 (P)+1 分超过数组的最后一个元素对象,如果表达式 Q 指向一个数组的最后一个元素对象,表达式 (Q)-1 指向数组对象的最后一个元素.如果指针操作数和结果指向相同的元素数组对象,或最后一个数组对象的元素,评估不应产生溢出;否则,行为是未定义.

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integral expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

(强调我的)

当然,这是针对operator+的.所以可以肯定的是,以下是标准关于数组下标的说明:

Of course, this is for operator+. So just to be sure, here's what the standard says about array subscripting:

5.2.1:1:

表达式 E1[E2]*((E1)+(E2))

当然,有一个明显的警告:您的示例实际上并未显示越界指针.它使用一个越过终点"指针,这是不同的.允许指针存在(如上所述),但就我所见,标准没有说明取消引用它.我能找到的最接近的是 3.9.2:3:

Of course, there's an obvious caveat: Your example doesn't actually show an out-of-bounds pointer. it uses a "one past the end" pointer, which is different. The pointer is allowed to exist (as the above says), but the standard, as far as I can see, says nothing about dereferencing it. The closest I can find is 3.9.2:3:

[注意:例如,数组末尾的地址(5.7)将被视为指向可能位于该地址的数组元素类型的不相关对象.——结尾说明]

[Note: for instance, the address one past the end of an array (5.7) would be considered to point to an unrelated object of the array’s element type that might be located at that address. —end note ]

在我看来,这意味着是的,您可以合法地取消引用它,但读取或写入该位置的结果未指定.

Which seems to me to imply that yes, you can legally dereference it, but the result of reading or writing to the location is unspecified.

感谢 ilproxyil 更正了这里的最后一点,回答了您问题的最后一部分:

Thanks to ilproxyil for correcting the last bit here, answering the last part of your question:

  • array + 5 实际上并没有取消引用任何东西,它只是创建一个指向末尾的指针数组.
  • &array[4] + 1 取消引用array+4(这是完全安全的),获取该左值的地址,并且在该地址上添加一个,即导致最后一个指针(但那个指针永远不会得到取消引用.
  • &array[5] 取消引用数组+5(据我所知这是合法的,并导致一个不相关的对象数组的元素类型",作为上面说),然后取该元素的地址,它也看起来足够合法.
  • array + 5 doesn't actually dereference anything, it simply creates a pointer to one past the end of array.
  • &array[4] + 1 dereferences array+4 (which is perfectly safe), takes the address of that lvalue, and adds one to that address, which results in a one-past-the-end pointer (but that pointer never gets dereferenced.
  • &array[5] dereferences array+5 (which as far as I can see is legal, and results in "an unrelated object of the array’s element type", as the above said), and then takes the address of that element, which also seems legal enough.

所以他们做的事情并不完全相同,尽管在这种情况下,最终结果是一样的.

So they don't do quite the same thing, although in this case, the end result is the same.

这篇关于通过下标获取最后一个数组元素的地址:C++ 标准是否合法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆