由于 'm' 是一个 int,它不应该将 p2-p1 作为输入,因为 p1 和 p2 都是指针并且 m 是一个整数,它应该给出一个错误,例如“从 'int' 到 'int' 的无效转换”但是不是。为什么?
C++ 规范声明这是合法的。
来自 C++11 规范 5.7.6:
当两个指向同一个数组对象的元素的指针相减时,结果就是两个数组元素的下标之差。结果的类型是实现定义的有符号整数类型;此类型应与标头 (18.2) 中定义为 std::ptrdiff_t 的类型相同。
...稍后在该段中...
除非两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,否则行为是未定义的。
p2 - p1 的结果与 std::ptrdiff_t 的类型相同,但没有说明编译器不能将其定义为
namspace std {
typedef ptrdiff_t int;
}
但是,您也无法保证这将适用于所有平台。例如,某些平台(尤其是 64 位平台)将对 ptrdiff_t 使用 long。在这些平台上,您的代码将无法编译,因为它依赖于 ptrdiff_t 的实现定义类型。
至于您的第二个问题,C++ 规范 5.7.6 中的措辞暗示了为什么它们以它们的工作方式工作。措辞表明该语言的作者希望指针算术支持快速算术,同时通过数组工作。因此,当在操作数组的上下文中使用时,定义了指针减法的结果以产生方便的结果。您可以构建一种语言,其中两个指针之间的差异是它们的内存地址(以字节为单位)之间的差异,并且您将拥有一致的工作语言。然而,一门好的语言总是能物超所值。作者认为对数组的干净操作比能够获得字节差更有价值。例如:
double* findADouble(double* begin, double* end, double valueToSearchFor)
{
for (double* iter = begin; iter != end; iter++) {
if (*iter == valueToSearchFor)
return iter;
}
return 0;
}
必须有一个 sizeof,我们必须使用 += 而不是 ++。
double* findADouble(double* begin, double* end, double valueToSearchFor)
{
for (double* iter = begin; iter != end; iter += sizeof(double)) {
if (*iter == valueToSearchFor)
return iter;
}
return 0;
}
在他们的决定中也值得注意:当规则是在 C 中创建时,优化编译器并不擅长他们的工作。iter += sizeof(double) 可以编译成比 ++iter 效率低得多的汇编代码,即使这两个操作基本上做同样的事情。现代优化器对此没有任何问题,但语法仍然存在。