2个指针,0个字节的差异但不相等

时间:2017-04-12 03:48:20

标签: c++ pointers undefined-behavior

在C ++中,我完全知道指针减法仅在数组中有效,下面的代码是未定义的行为。我知道试图推断未定义的行为是毫无意义的,但我相信提出以下问题是有价值的。

#include <cstddef>
#include <iostream>
#include <iomanip>

int main()
{
    long a = 1;
    long b = 1;

    std::cout << (char*)(&b) - (char*)(&a)  << '\n'; //prints 8, ok we're 8 bytes apart

    char* aPlus8 = (char*)&a + 8; //bump up 8 bytes
    char* bPtr = (char*)&b;

    std::cout << "diff in bytes = " << (bPtr - aPlus8)  << '\n';            //prints 0. All good, looks like we're there
    std::cout << "but are they the same? = " << (bPtr == aPlus8)  << '\n';  //but are we ?
}

最后一行bPtr == aPlus8返回false,尽管字节差异为0.是否可能有解释? (除了“因为它是未定义的行为”)

这是使用g++ -std=c++14 -O3 -Wall -pedantic编译的。如果我改变优化级别,那么输出也会发生变化。

2 个答案:

答案 0 :(得分:6)

优化程序很可能注意到bPtraPlus8不可能相等,因此将(bPtr == aPlus8)替换为false以保存一些CPU指令。

请注意,这种优化不仅可以节省CPU指令 - 想象一下,如果您有类似

的内容
if(bPtr == aPlus8)
{
    // lots of complicated code here
}

然后优化器就能删除if语句中的所有代码。这就是为什么这种优化和类似的优化是有用的。

实际上,在现代编译器中,未定义行为的主要影响之一是它允许优化器找到简化代码的方法。

答案 1 :(得分:0)

C标准,可能是C ++标准,明确指出如果两个指针可以“合法地”访问相同的对象,它们将比较相等,并且还清楚地表明指向一个对象的指针有时可能比较等于指针“刚过“另一个对象,即使他们不能合法地访问同一个对象。在大多数情况下,设计合理的代码不应该关心指向对象的指针是否会与“刚刚过去”另一个指针的指针进行比较,因此我不认为这两个标准是否明确:

  1. 如果两个对象不相关,那么一个刚刚过去的指针和一个指向另一个的指针之间的每个单独的比较应被视为产生一个独立的未指定结果(意味着指针等于运算符不需要表现为等价关系)。

  2. 可以通过“direct”和“just-past”指针连接的不相关对象集是未指定的,但是涉及这些指针的比较将产生与某些这样的集合一致的结果(意味着指针等于运算符会有效地定义了等价关系。)

  3. 指针等式的语义以某种方式定义,比#1更精确,但不如#2精确。

  4. 标准故意避免要求所有实现都适用于系统编程,并且如果允许编译器允许进行涉及指向不相关对象的指针的所有比较报告它们不相等,则编译器可以生成更有效的代码。如果系统编程之类的目的代码可以指定在没有标准通常要求的某些语义保证之外它将无法工作,并且任何不能遵守这些保证的实现必须拒绝,那么有一个标准手段将是有帮助的。完全汇编。我不知道在C或C ++中有什么方法可以指定代码需要指针相等运算符表现为等价关系,但C ++还有其他比较指针的方法,例如std::less,这提供了更强的保证比它的运营商。