对超出范围的指针进行比较是否明确定义?

时间:2012-12-21 21:01:36

标签: c++ language-lawyer

给出以下代码:

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本身未定义的行为?)

3 个答案:

答案 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]:

  

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

简而言之,只计算一个越界指针有未定义的行为;在那之后你对那个指针执行什么操作并不重要。