C 或 C + + 保证数组 < array + SIZE?

假设您有一个数组:

int array[SIZE];

或者

int *array = new(int[SIZE]);

C 或 C + + 是否保证 array < array + SIZE,如果是,在哪里?

我理解,无论语言规范如何,许多操作系统都通过为内核保留虚拟地址空间的顶部来保证这一属性。我的问题是,这是否也是 语言所保证的,而不仅仅是绝大多数实现所保证的。

例如,假设一个操作系统内核位于低内存中,并且有时为了响应匿名内存的 mmap请求,将虚拟内存的最高页面提供给用户进程。如果 malloc::operator new[]直接调用 mmap来分配一个巨大的数组,并且数组的末端紧邻虚拟地址空间的顶端,使得 array + SIZE绕到零,这是否意味着语言的不兼容实现?

澄清一下

注意,问题是 没有询问 array+(SIZE-1)array+(SIZE-1)是数组最后一个元素的地址。那一个肯定比 array大。问题是关于指针 超过数组末尾的,或者当 p是指向非数组对象的指针时也是关于指针 p+1的(所选答案所指向的标准部分清楚地表明以同样的方式处理该指针)。

Stackoverflow 要求我澄清为什么这个问题与 这个不同。另一个问题是如何实现指针的总排序。另一个问题实质上可以归结为一个库如何实现 std::less,以至于它甚至可以对指向不同分配对象的指针起作用,标准规定只能比较相等性,不能大于或小于相等性。

相比之下,我的问题是,超过数组末尾的值是否总是保证大于该数组。不管我的问题的答案是“是”还是“否”,实际上并不会改变您实现 std::less的方式,因此另一个问题似乎并不相关。如果与数组末尾的数据进行比较是非法的,那么在这种情况下,std::less可以简单地展示未定义行为。(另外,标准库通常是由与编译器相同的人实现的,因此可以自由地利用特定编译器的属性。)

6729 次浏览

C 部分要求这样 6.5.8部分说:

指向下标值较大的数组元素的指针比指向下标值较低的同一数组元素的指针大

我相信在 C + + 规范中也有类似的东西。

这一要求有效地防止了在通用硬件上分配围绕地址空间的对象,因为要实现有效实现关系运算子所需的所有簿记功能是不切实际的。

是的,从 6.5.8区。

如果表达式 P 指向数组对象的元素 表达式 Q 指向同一数组的最后一个元素 对象,则指针表达式 Q + 1比 P 大。

表达式 array是 P。表达式 array + SIZE - 1指向 array的最后一个元素 Q。 因此:

array + SIZE = array + SIZE - 1 + 1 = Q + 1 > P = array

数组中保证有连续的内存空间。之后 c + + 03左右的向量保证对于它的 &vec[0] ... &vec[vec.size() - 1]也有一个。这自动意味着你所问的是真实的
这叫做连续存储,可以在这里找到矢量
Http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0944r0.html

一个向量的元素是连续存储的,这意味着如果 v 是一个向量 < T,分配器 > ,其中 T 是另一种类型,而不是 bool,那么对于所有0 < = n < v.size () ,它服从恒等式 & v [ n ] = = & v [0] + n。据推测,再花五年时间研究连接性与缓存之间的相互作用,就可以向工作组21明确表明,需要强制实施连接性,并明确禁止非连续向量的实施。

后者来自标准的文档 C + + 03,我猜对了。

这是在 C + + 中从7.6.6.4(当前 C + + 23草案的 p139)定义的:

当在指针类型的表达式 P 中加入或减去具有整数类型的表达式 J 时,结果的类型为 P。

(4.1)ー如果 P 的值为空指针值,而 J 的值为0,则结果为空指针值。

(4.2)-否则,如果 P 指向一个有 n 个元素的数组对象 x 的数组元素 i (9.3.4.5) ,则表达式 P + J 和 J + P (其中 J 有值 j)指向(可能假设的)数组元素 i + j,如果0 < = i + j < = n,则 P-J 指向(可能假设的)数组元素 i-j,如果0 < = i-j < = n。

(4.3)-否则,行为是未定义的。

注意,4.2显式有“ < = n”,而不是“ < n”。对于大于 size ()的任何值都没有定义,但是对 size ()进行了定义。

数组元素的顺序在7.6.9(p141)中定义:

(4.1)如果两个指针指向同一数组的不同元素或其子对象,则需要指向下标较高的元素的指针进行比较。

这意味着,对于所有定义明确的 n > 0的情况,假设的元素 n 将比数组本身(元素0)大。

SIZE为零时,保证不适用于案例 int *array = new(int[SIZE]);

new int[0]的结果必须是一个有效的指针,可以将 0添加到其中,但是在这种情况下,array == array + SIZE和严格的小于测试将产生 false

C + + 中的相关规则是 [ expr.rel ]/4.1:

如果两个指针指向同一数组的不同元素或其子对象,则需要指向下标较高的元素的指针进行比较。

上述规则似乎只涵盖指向数组元素的指针,而 array + SIZE不指向数组元素。但是,正如在 脚注中提到的,这里将 one-past-the-end 指针视为数组元素。[基础化合物]/3中有关的语言规则是:

为了进行指针运算([ expr.add ])和比较([ expr.rel ] ,[ expr.eq ]) ,一个指针越过 N元素的数组 x的最后一个元素的末尾,被认为等价于一个指向假设的 x的数组元素 N的指针,而一个不是数组元素的 T类型的对象被认为属于一个具有一个 T类型元素的数组。

所以 C + + 保证 array + SIZE > array(至少在 SIZE > 0时)和 &x + 1 > &x对于任何对象 x