C 或 C++ 是否保证数组 < 数组 + SIZE?
Does C or C++ guarantee array < array + SIZE?
假设你有一个数组:
int array[SIZE];
或
int *array = new(int[SIZE]);
C 或 C++ 是否保证 array < array + SIZE
,如果是,在哪里?
我了解到,无论语言规范如何,许多操作系统都通过为内核保留虚拟地址 space 的顶部来保证此 属性。我的问题是,这是否也由语言保证,而不仅仅是由绝大多数实现保证。
举个例子,假设 OS 内核位于低内存中,有时会响应 mmap
对匿名内存的请求,将最高的虚拟内存页面提供给用户进程。如果malloc
或::operator new[]
直接调用mmap
分配一个巨大的数组,数组的末尾紧靠虚拟地址space的顶部使得array + SIZE
回绕到零,这是否相当于语言的不兼容实现?
澄清
注意问题是不是问的是array+(SIZE-1)
,是数组最后一个元素的地址。那一个肯定大于array
。问题是关于指针 数组末尾的一个指针 ,或者当 p
是指向非数组对象的指针时 p+1
(该部分所选答案所指向的标准明确表示以相同方式处理)。
Whosebug 要求我澄清为什么这个问题与 this one 不同。另一个问题询问如何实现指针的总排序。另一个问题本质上归结为库如何实现 std::less
使其甚至适用于指向不同分配对象的指针,标准规定只能比较相等性,而不是大于和小于。
相比之下,我的问题是关于数组末尾的一个是否总是保证大于数组。我的问题的答案是肯定还是否定实际上并不会改变您实施 std::less
的方式,因此其他问题似乎并不相关。如果与数组末尾的一个进行比较是非法的,那么 std::less
在这种情况下可能会简单地表现出未定义的行为。 (此外,标准库通常由与编译器相同的人实现,因此可以自由利用特定编译器的属性。)
C 需要这个。 6.5.8 para 5 部分说:
pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values
我确定 C++ 规范中有类似的内容。
此要求有效地阻止了在通用硬件上分配环绕地址 space 的对象,因为实现有效实现关系运算符所需的所有簿记是不切实际的。
是的。来自 6.5.8 para 5.
部分
If the expression P points to an element of an array object
and the expression Q points to the last element of the same array
object, the pointer expression Q+1 compares greater than P.
表达式array
是P,表达式array + SIZE - 1
指向array
的最后一个元素,即Q。
因此:
array + SIZE = array + SIZE - 1 + 1 = Q + 1 > P = array
数组保证里面有连续的内存space。在 c++03 左右之后,vectors 也保证有一个 &vec[0] ... &vec[vec.size() - 1]
。这自动意味着你问的是真的
它被称为连续存储。可以在这里找到矢量
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0944r0.html
The elements of a vector are stored contiguously, meaning that if v is a vector<T, Allocator> where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size(). Presumably five more years of studying the interactions of contiguity with caching made it clear to WG21 that contiguity needed to be mandated and non-contiguous vector implementation should be clearly banned.
后者来自标准文档。 C++03 我猜对了
这是在 C++ 中定义的,来自 7.6.6.4(当前 C++23 draft 的 p139):
When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.
(4.1) — If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.
(4.2) — Otherwise, if P points to an array element i of an array object x with n elements (9.3.4.5) the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) array element i + j of x if 0 <= i + j <= n and the expression P - J points to the (possibly-hypothetical) array element i − j of x if 0 <= i − j <= n.
(4.3) — Otherwise, the behavior is undefined.
请注意,4.2 明确包含“<= n”,而不是“< n”。对于任何大于 size() 的值都是未定义的,但是对于 size() 是有定义的。
数组元素的顺序在 7.6.9 (p141) 中定义:
(4.1) If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript is required to compare greater.
这意味着对于 n > 0 的所有明确定义的情况,假设元素 n 将比数组本身(元素 0)更大。
当 SIZE
为零时,保证不适用于 int *array = new(int[SIZE]);
的情况。
new int[0]
的结果需要是一个可以添加 0
的有效指针,但在这种情况下 array == array + SIZE
,严格小于测试将产量 false
.
C++中的相关规则是[expr.rel]/4.1:
If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript is required to compare greater.
以上规则似乎只涵盖指向数组元素的指针,array + SIZE
不指向数组元素。但是,正如the footnote, a one-past-the-end pointer is treated as if it were an array element here. The relevant language rule is in [basic.compound]/3中提到的:
For purposes of pointer arithmetic ([expr.add]) and comparison ([expr.rel], [expr.eq]), a pointer past the end of the last element of an array x
of n elements is considered to be equivalent to a pointer to a hypothetical array element n of x
and an object of type T
that is not an array element is considered to belong to an array with one element of type T
.
所以 C++ 保证 array + SIZE > array
(至少在 SIZE > 0
时),并且 &x + 1 > &x
对于任何对象 x
.
假设你有一个数组:
int array[SIZE];
或
int *array = new(int[SIZE]);
C 或 C++ 是否保证 array < array + SIZE
,如果是,在哪里?
我了解到,无论语言规范如何,许多操作系统都通过为内核保留虚拟地址 space 的顶部来保证此 属性。我的问题是,这是否也由语言保证,而不仅仅是由绝大多数实现保证。
举个例子,假设 OS 内核位于低内存中,有时会响应 mmap
对匿名内存的请求,将最高的虚拟内存页面提供给用户进程。如果malloc
或::operator new[]
直接调用mmap
分配一个巨大的数组,数组的末尾紧靠虚拟地址space的顶部使得array + SIZE
回绕到零,这是否相当于语言的不兼容实现?
澄清
注意问题是不是问的是array+(SIZE-1)
,是数组最后一个元素的地址。那一个肯定大于array
。问题是关于指针 数组末尾的一个指针 ,或者当 p
是指向非数组对象的指针时 p+1
(该部分所选答案所指向的标准明确表示以相同方式处理)。
Whosebug 要求我澄清为什么这个问题与 this one 不同。另一个问题询问如何实现指针的总排序。另一个问题本质上归结为库如何实现 std::less
使其甚至适用于指向不同分配对象的指针,标准规定只能比较相等性,而不是大于和小于。
相比之下,我的问题是关于数组末尾的一个是否总是保证大于数组。我的问题的答案是肯定还是否定实际上并不会改变您实施 std::less
的方式,因此其他问题似乎并不相关。如果与数组末尾的一个进行比较是非法的,那么 std::less
在这种情况下可能会简单地表现出未定义的行为。 (此外,标准库通常由与编译器相同的人实现,因此可以自由利用特定编译器的属性。)
C 需要这个。 6.5.8 para 5 部分说:
pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values
我确定 C++ 规范中有类似的内容。
此要求有效地阻止了在通用硬件上分配环绕地址 space 的对象,因为实现有效实现关系运算符所需的所有簿记是不切实际的。
是的。来自 6.5.8 para 5.
部分If the expression P points to an element of an array object and the expression Q points to the last element of the same array object, the pointer expression Q+1 compares greater than P.
表达式array
是P,表达式array + SIZE - 1
指向array
的最后一个元素,即Q。
因此:
array + SIZE = array + SIZE - 1 + 1 = Q + 1 > P = array
数组保证里面有连续的内存space。在 c++03 左右之后,vectors 也保证有一个 &vec[0] ... &vec[vec.size() - 1]
。这自动意味着你问的是真的
它被称为连续存储。可以在这里找到矢量
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0944r0.html
The elements of a vector are stored contiguously, meaning that if v is a vector<T, Allocator> where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size(). Presumably five more years of studying the interactions of contiguity with caching made it clear to WG21 that contiguity needed to be mandated and non-contiguous vector implementation should be clearly banned.
后者来自标准文档。 C++03 我猜对了
这是在 C++ 中定义的,来自 7.6.6.4(当前 C++23 draft 的 p139):
When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.
(4.1) — If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.
(4.2) — Otherwise, if P points to an array element i of an array object x with n elements (9.3.4.5) the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) array element i + j of x if 0 <= i + j <= n and the expression P - J points to the (possibly-hypothetical) array element i − j of x if 0 <= i − j <= n.
(4.3) — Otherwise, the behavior is undefined.
请注意,4.2 明确包含“<= n”,而不是“< n”。对于任何大于 size() 的值都是未定义的,但是对于 size() 是有定义的。
数组元素的顺序在 7.6.9 (p141) 中定义:
(4.1) If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript is required to compare greater.
这意味着对于 n > 0 的所有明确定义的情况,假设元素 n 将比数组本身(元素 0)更大。
当 SIZE
为零时,保证不适用于 int *array = new(int[SIZE]);
的情况。
new int[0]
的结果需要是一个可以添加 0
的有效指针,但在这种情况下 array == array + SIZE
,严格小于测试将产量 false
.
C++中的相关规则是[expr.rel]/4.1:
If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript is required to compare greater.
以上规则似乎只涵盖指向数组元素的指针,array + SIZE
不指向数组元素。但是,正如the footnote, a one-past-the-end pointer is treated as if it were an array element here. The relevant language rule is in [basic.compound]/3中提到的:
For purposes of pointer arithmetic ([expr.add]) and comparison ([expr.rel], [expr.eq]), a pointer past the end of the last element of an array
x
of n elements is considered to be equivalent to a pointer to a hypothetical array element n ofx
and an object of typeT
that is not an array element is considered to belong to an array with one element of typeT
.
所以 C++ 保证 array + SIZE > array
(至少在 SIZE > 0
时),并且 &x + 1 > &x
对于任何对象 x
.