给出以下代码:
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 < begin
和p > end
)是否定义明确?或者此代码是否具有未定义的行为,因为指针已经超过了数组的末尾?
如果比较定义明确,那么定义是什么?
(额外信用:评估begin + 2000
本身未定义的行为?)
答案 0 :(得分:10)
我将采用C++11标准。根据第5.7节(附加操作数)第5段,在您进行比较之前,*p = begin + 2000
的行为首先是未定义的:
如果指针操作数和结果都指向了元素 相同的数组对象,或者超过数组对象的最后一个元素, 评估不得产生溢流;否则,行为 是未定的。
答案 1 :(得分:6)
对begin+2000
的评估是未定义的,它已超过数组的末尾 - 您可以在结束时达到一个,但不能进一步。
来自C ++11§5.7/ 5 添加运算符:
当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向偏离原始元素的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式。 [...]如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为是 未定义强>
对于要指定的指针比较,假设您有有效的指针开始,它们本质上需要指向同一个数组(或指向结尾的指针),或指向同一访问控制的非静态数据成员的指针相同的对象(除非它是一个联盟...)。
详情见§5.9/ 2 关系运算符:
可以比较相同类型的对象或函数(指针转换后)的指针,结果定义如下:
- 如果同一类型的两个指针p和q指向同一个对象或函数,或两者都指向一个过去 在相同数组的末尾,或者都是空的,那么p&lt; = q和p&gt; = q两者都产生真和p&lt; q和p&gt; q 两者都是假的。
- 如果同一类型的两个指针p和q指向不是同一成员的不同对象 对象或同一数组的元素或不同的函数,或者如果只有其中一个为null,则为结果 p&lt; q,p&gt; q,p&lt; = q和p&gt; = q未指定。
- 如果两个指针指向同一对象的非静态数据成员,或指向子对象或数组元素 这些成员,递归地,指向后面声明的成员的指针比较大提供的 两名成员具有相同的访问控制权(第11条),并且他们的班级不是工会。
- 如果两个指针指向具有不同访问控制的同一对象的非静态数据成员 (第11条)结果未指明。 - 如果两个指针指向同一个union对象的非静态数据成员,则它们比较相等(之后) 如有必要,转换为void *。如果两个指针指向同一个数组或超出的数组 在数组的末尾,指向具有较高下标的对象的指针比较高。
- 未指定其他指针比较。
答案 2 :(得分:3)
您的程序行为未定义,但不是因为比较。
表达式begin + 2000
的计算具有未定义的行为,因为结果将指向超过1024个元素数组末尾的多个元素。
引用C ++ 11(实际上是N3485草案),5.7p4 [expr.add]:
添加或减去具有整数类型的表达式时 从指针开始,结果具有指针操作数的类型。 [...] 如果指针操作数和结果都指向了元素 相同的数组对象,或者超过数组对象的最后一个元素, 评估不得产生溢出;否则,行为 未定义。
简而言之,只计算一个越界指针有未定义的行为;在那之后你对那个指针执行什么操作并不重要。