指针值是不同的,但他们比较相等。 为什么?

一个简短的例子输出一个奇怪的结果!

#include <iostream> using namespace std; struct A { int a; }; struct B { int b; }; struct C : A, B { int c; }; int main() { C* c = new C; B* b = c; cout << "The address of b is 0x" << hex << b << endl; cout << "The address of c is 0x" << hex << c << endl; if (b == c) { cout << "b is equal to c" << endl; } else { cout << "b is not equal to c" << endl; } } 

我非常惊讶的是输出结果如下:

 The address of b is 0x003E9A9C The address of c is 0x003E9A98 b is equal to c 

我想知道的是:

0x003E9A9C不等于0x003E9A98,但输出是“b等于c”

一个C对象包含两个typesAB子对象。 显然,这些地址必须有不同的地址,因为两个单独的对象不能有相同的地址。 所以最多只能有一个与C对象相同的地址。 这就是为什么打印指针给出不同的值。

比较指针不会简单地比较它们的数值。 只有同一types的指针可以比较,所以第一个指针必须转换为匹配另一个指针。 在这种情况下, c被转换为B* 。 这与用于初始化b转换完全相同:它调整指针值,使其指向B子对象而不是C对象,现在两个指针比较相等。

Ctypes对象的内存布局将如下所示:

 | <---- C ----> | |-A: a-|-B: b-|- c -| 0 4 8 12 

我从对象的地址(在像你的sizeof(int)= 4)的平台中添加了字节偏移量。

在你的主体中,你有两个指针,为了清晰起见,我将它们重命名为pbpcpc指向整个C对象的开始,而pb指向B子对象的开始:

  | <---- C ----> | |-A: a-|-B: b-|- c -| 0 4 8 12 pc-^ pb-^ 

这就是他们的价值观不同的原因。 3E9A98 + 4是3E9A9C,以hex表示。

如果现在比较这两个指针,编译器会看到一个B*C*之间的比较,它们是不同的types。 所以它必须应用隐式转换,如果有的话。 pb不能被转换成C* ,但反过来也是可能的 – 它将pc转换成B* 。 这个转换会给出一个指针,指向pc指向的B子对象 – 当你定义B* pb = pc;时,它是相同的隐式转换B* pb = pc; 。 结果等于pb ,显然是:

  | <---- C ----> | |-A: a-|-B: b-|- c -| 0 4 8 12 pc-^ pb-^ (B*)pc-^ 

所以比较这两个指针时,编译器实际上比较了转换的指针,它们是相等的。

我知道有一个答案,但也许这将是一个例子更直接和备份。

if (b == c)c操作数中有一个从C*B*的隐式转换,

如果你使用这个代码:

 #include <iostream> using namespace std; struct A { int a; }; struct B { int b; }; struct C : A, B { int c; }; int main() { C* c = new C; B* b = c; cout << "The address of b is 0x" << hex << b << endl; cout << "The address of c is 0x" << hex << c << endl; cout << "The address of (B*)c is 0x" << hex << (B*)c << endl; if (b == c) { cout << "b is equal to c" << endl; } else { cout << "b is not equal to c" << endl; } } 

你得到:

 The address of b is 0x0x88f900c The address of c is 0x0x88f9008 The address of (B*)c is 0x0x88f900c b is equal to c 

所以c转换成B*types的地址与b相同。 正如所料。

如果我可以加上Mike的优秀答案,如果你把他们视为void*那么你会得到你预期的行为:

 if ((void*)(b) == (void*)(c)) ^^^^^^^ ^^^^^^^ 

版画

 b is not equal to c 

在C(语言)上做类似的事情实际上使得编译器感到恼火,因为比较了不同types的指针。

我有:

 warning: comparison of distinct pointer types lacks a cast [enabled by default] 

在计算(或者说,我们应该在math中说)可以有许多平等的概念。 任何对称,自反和传递的关系都可以用作平等。

在你的程序中,你正在检查两个有点不同的概念:按位实现的标识(两个指向完全相同的地址)与基于对象标识的另一种相等,它允许通过不同的引用静态types,要正确地视为引用同一个对象。

这些不同types的视图使用不具有相同地址值的指针,因为它们locking在对象的不同部分。 编译器知道这一点,所以它会为考虑到这个偏移量的相等比较生成正确的代码。

这是由inheritance带来的对象结构,这使得有必要有这些抵消。 当有多个基地(由于多重inheritance),只有一个基地可以在对象的低地址,以便指向基地部分的指针是相同的指向派生的对象。 其他基地部分是在对象的其他地方。

所以,根据对象的面向对象视图,指针的按位比较不会产生正确的结果。

这里有一些很好的答案,但有一个简短的版本。 “两个对象是相同的”并不意味着他们有相同的地址。 这意味着将数据放入其中并从中取出数据是等同的。