C++ 为什么指针减法在C++;?

C++ 为什么指针减法在C++;?,c++,pointers,C++,Pointers,对于下面的示例,什么可能导致未定义的行为?为什么? #include <cstddef> #include <iostream> template <typename Ty> bool in_range(const Ty *test, const Ty *r, size_t n) { return 0 < (test - r) && (test - r) < (std::ptrdiff_t)n; } void

对于下面的示例,什么可能导致
未定义的行为
?为什么?

#include <cstddef> 
#include <iostream> 

template <typename Ty> 
bool in_range(const Ty *test, const Ty *r, size_t n) 
{ 
    return 0 < (test - r) && (test - r) < (std::ptrdiff_t)n; 
}

void f() { 
     double foo[10]; 
     double *x = &foo[0]; 
     double bar; 
     std::cout << std::boolalpha << in_range(&bar, x, 10);
}
#包括
#包括
模板
范围内的布尔值(常数*测试、常数*r、大小)
{ 
返回0<(test-r)和&(test-r)<(std::ptrdiff_t)n;
}
void f(){
双福[10];
double*x=&foo[0];
双杠;

std::cout指针算术,包括两个指针的减法,仅当指针指向同一数组中的元素,或指向该数组末尾的元素时才定义。在此上下文中,标量计为大小为1的数组


在任何其他实例中允许指针运算是毫无意义的。这样做将不必要地约束C的内存模型,并且可以减少其灵活性和能力,以向异域架构传送。

< P>代码,正如您编写的,对于C++来说,答案基本上是相同的:如果C和O,您得到定义的行为。仅当所涉及的两个指针引用同一数组的部分,或一个指针超过其末端时(如@bathsheba所述,非数组对象被视为与一个项的数组相同)


然而,C++确实增加了一个可能很有用的地方:即使在这种情况下,减法和有序比较(例如,
未定义的行为通常不会导致崩溃,而是导致无意义或不一致的结果)

在大多数现代体系结构中,减去2个不相关的指针只计算地址差除以指针类型的大小,大致如下:

    A *p1, *p2;
    ...
    ptrdiff_t diff = ((intptr_t)p2 - (intptr_t)p1) / (intptr_t)sizeof(*p1);
英特尔的16位分段中型和大型机型就是这种行为出人意料的架构示例:

  • 在386及其32位机型出现之前,这些机型曾在PC机上流行
  • 远指针存储在两个部分:16位段(或保护模式下的选择器)和16位偏移量
  • 比较两个指针是否相等需要两个单独的比较指令以及段和偏移量的条件跳转
  • 将指针与
    NULL
    进行比较通常优化为将段部分与0进行单个比较
  • 减去2个指针并比较相对位置仅在偏移部分执行,这使得无声假设两个指针指向同一数组,因此具有相同的段

  • 在您的示例中,两个对象都有自动存储,因此它们都在同一个段中,指向
    SS
    ,但是对于从堆中分配的两个对象,您可以拥有
    p,当然,必然的结果是
    位于\u范围()
    OP呈现的函数几乎完全没有意义。您需要知道答案才能安全地调用该函数。@coderredoc:您是否听了特定的标记?如果听了,您会得到一个“新问题”通知,就像你在较小的网站上做的那样。我只是仔细听-如果我在c中看到一个问题,我会尝试回答…顺便说一句,回答得很好。@coderredoc Stackoverflow删除上一个beta版,他对问题排序非常有用,但对我来说已经足够了。活动问题重新组合新的和更新的问题,以及相关标签的新的和更新的答案。你只需要等着看一个新的事件,点击它。“StAdvuru:就是这个!你应该在你提到的问题上找到答案,因为C++的答案和C一样,答案是在那里。不应该是代码> STD::LasixErrar()(开始,测试)< /代码>(注:星号)?@qbolec:是的,至少在大多数情况下是这样。我编辑过。谢谢。
    template <typename Ty> 
    bool in_range(const Ty *test, const Ty *begin, const Ty *end) 
    { 
        return std::less_equal<Ty *>()(begin, test) && std::less<Ty *>()(test, end);
    }
    
    template <typename Ty> 
    bool in_range(const Ty *test, const Ty *r, size_t n) 
    { 
        auto end = r + n;
        return std::less_equal<Ty *>()(r, test) && std::less<Ty *>()(test, end);
    }
    
    template <class Ty, size_t N>
    bool in_range(Ty (&array)[N], Ty *test) {
        return  std::less_equal<Ty *>()(&array[0], test) && 
                std::less<Ty *>()(test, &array[0] + N);
    }
    
    int foo[10];
    int *bar = &foo[4];
    
    std::cout << std::boolalpha << in_range(foo, bar) << "\n"; // returns true
    
    int foo[10];
    int bar;
    int *baz = &foo[0];
    int *ptr = new int[20];
    
    std::cout << std::boolalpha << in_range(bar, baz) << "\n"; // won't compile
    std::cout << std::boolalpha << in_range(ptr, baz) << "\n"; // won't compile either
    
    template <class Ty, size_t N>
    bool in_range(Ty (&array)[N], Ty *test) {
        return  std::less_equal<Ty *>()(&array[0], test) &&
                std::less<Ty *>()(test, &array[0]+ N);
    }
    
    template <class Ty>
    bool in_range(Ty &a, Ty *b) { return &a == b; }
    
    template <class Ty>
    bool in_range(Ty a, Ty b, size_t N) {
        return std::less_equal<Ty>()(a, b) && 
               std::less<Ty>()(b, a + N);
    }
    
    void f() { 
         double foo[10]; 
         double *x = &foo[0]; 
         double bar;
         double *baz = new double[20];
    
         std::cout << std::boolalpha << in_range(foo, x) << "\n";
         std::cout << std::boolalpha << in_range(bar, x) << "\n";
         std::cout << std::boolalpha << in_range(baz, x, 20) << "\n";
    }
    
        A *p1, *p2;
        ...
        ptrdiff_t diff = ((intptr_t)p2 - (intptr_t)p1) / (intptr_t)sizeof(*p1);