13

给定以下代码:

char buffer[1024];
char * const begin = buffer;
char * const end = buffer + 1024;
char *p = begin + 2000;
if (p < begin || p > end)
    std::cout << "pointer is out of range\n";

执行的比较 (p < beginp > end) 是否明确?或者此代码是否具有未定义的行为,因为指针已超出数组末尾?

如果比较定义明确,那么该定义是什么?

(额外的功劳:对自身的评估是begin + 2000不确定的行为吗?)

4

3 回答 3

10

我将假设C++11标准。根据第 5.7 节(加法操作数)第 5 段*p = begin + 2000,在您进行比较之前,首先未定义的行为:

如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则计算不应产生溢出;否则,行为是未定义的。

于 2012-12-21T21:10:39.177 回答
6

的评估begin+2000是未定义的,它超过了数组的末尾 - 你可以在末尾上加一个,但不能更远。

从 C++11 §5.7/5加法运算符

当具有整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果和原始数组元素的下标之差等于积分表达式。[...] 如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则评估不应产生溢出;否则,行为是 undefined

对于要指定的指针比较,假设您有有效的指针以开始,它们本质上需要是指向同一个数组(或末尾的一个)的指针,或者是指向同一访问控制的非静态数据成员的指针对象(除非它是一个联合......)。

详细信息在 §5.9/2关系运算符中:

可以比较指向相同类型的对象或函数的指针(指针转换后),结果定义如下:

  • 如果相同类型的两个指针 p 和 q 指向同一个对象或函数,或者都指向同一个数组末尾之后的一个,或者都为 null,则 p<=q 和 p>=q 都产生 true 和 p <q 和 p>q 都产生错误。
  • 如果相同类型的两个指针 p 和 q 指向不同的对象,这些对象不是同一对象的成员或同一数组的元素或指向不同的函数,或者如果其中只有一个为空,则 p<q, p 的结果>q、p<=q 和 p>=q 未指定。
  • 如果两个指针指向同一个对象的非静态数据成员,或者这些成员的子对象或数组元素,递归地,如果两个成员具有相同的访问控制(第 11 条)和前提是他们的班级不是工会。
  • 如果两个指针指向具有不同访问控制(第 11 条)的同一对象的非静态数据成员,则结果未指定。— 如果两个指针指向同一个联合对象的非静态数据成员,它们比较相等(如果需要,在转换为 void* 之后)。如果两个指针指向同一个数组的元素或一个超出数组末尾的元素,则指向具有较高下标的对象的指针比较高。
  • 其他指针比较未指定。
于 2012-12-21T21:09:13.873 回答
3

您的程序的行为是未定义的,但不是因为比较。

表达式的评估begin + 2000具有未定义的行为,因为结果将指向超过 1024 个元素数组末尾的多个元素。

引用 C++11(实际上是N3485草案),5.7p4 [expr.add]:

当具有整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。[...] 如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则评估不应产生溢出;否则,行为未定义。

简而言之,仅计算越界指针具有未定义的行为;之后您对该指针执行的操作并不重要。

于 2012-12-21T22:39:50.627 回答