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

Joh*_*mew 13 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";
Run Code Online (Sandbox Code Playgroud)

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

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

(额外信用:评估begin + 2000自身未定义的行为?)

Dmi*_* B. 10

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

如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定.


Mat*_*Mat 6

评估begin+2000是未定义的,它将超过数组的末尾 - 你可以在结束时达到一个,但不能进一步.

来自C++11§5.7/ 5 附加运算符:

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

为了指定指针比较,假设你有有效的指针开始,它们基本上需要指向同一个数组(或一个超过结束的指针),或指向同一个访问控制的非静态数据成员的指针对象(除非它是一个联盟......).

详情见§5.9/ 2 关系运算符:

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

  • 如果相同类型的两个指针p和q指向同一个对象或函数,或者两个指针指向同一个数组的末尾,或者都是null,那么p <= q和p> = q都产生true和p <q和p> q都产生错误.
  • 如果同一类型的两个指针p和q指向不是同一个对象的成员或同一个数组的元素或不同函数的不同对象,或者只有其中一个为null,则p <q,p的结果> q,p <= q,p> = q未指定.
  • 如果两个指针指向同一对象的非静态数据成员,或者指向这些成员的子对象或数组元素,则递归地指向稍后声明的成员的指针比较更大,前提是两个成员具有相同的访问控制(第11条)和如果他们的班级不是工会.
  • 如果两个指针指向具有不同访问控制的同一对象的非静态数据成员(第11条),则结果未指定. - 如果两个指针指向同一个union对象的非静态数据成员,则它们比较相等(在转换为void*之后,如果需要).如果两个指针指向同一数组的元素或超出数组末尾的指针,则指向具有较高下标的对象的指针会比较高.
  • 其他指针比较未指定.

  • 至于为什么会这样,可以想象"缓冲区"可以在地址500处分配在仅2048字节大的存储器中.所以`begin`将是500,而`p`将是2500.但由于内存只有2048大(因此指针只有11位长),你实际得到的'p`是地址452 - *提前*'缓冲区'.(是的,这个例子是设计的,但有各种*实际*分段的内存方案不是*那些*不同.) (2认同)