指针值不同但它们相等.为什么?

xml*_*lmx 71 c++ pointers multiple-inheritance

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

#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;
    }
}
Run Code Online (Sandbox Code Playgroud)

令我非常惊讶的是输出应该如下:

The address of b is 0x003E9A9C
The address of c is 0x003E9A98
b is equal to c
Run Code Online (Sandbox Code Playgroud)

让我惊讶的是:

0x003E9A9C不等于0x003E9A98,但输出为"b等于c"

Mik*_*our 87

一个C对象包含两个子对象,类型AB.显然,这些必须具有不同的地址,因为两个单独的对象不能具有相同的地址; 所以最多其中一个可以与C对象具有相同的地址.这就是打印指针给出不同值的原因.

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


Arn*_*rtz 75

类型对象的内存布局C如下所示:

|   <---- C ---->   |
|-A: a-|-B: b-|- c -|
0      4      8     12
Run Code Online (Sandbox Code Playgroud)

我在对象的地址中添加了偏移量(在像你这样的平台中,sizeof(int)= 4).

在你的主,你有两个指针,我将它们重命名为pbpc的清晰度.pc指向整个C对象pb的开头,同时指向B子对象的开头:

   |   <---- C ---->   |
   |-A: a-|-B: b-|- c -|
   0      4      8     12
pc-^   pb-^
Run Code Online (Sandbox Code Playgroud)

这就是他们的价值观不同的原因.3E9A98 + 4是3E9A9C,十六进制.

如果你现在比较这两个指针,编译器将看到a B*和a 之间的比较C*,它们是不同的类型.所以它必须应用隐式转换(如果有的话).pb不能转换为a C*,但另一种方式是可能的 - 它转换pc为a B*.该转换将指向指向B子对象的指针pc- 无论指向何处- 它与您定义时使用的隐式转换相同B* pb = pc;.结果pb显然等于:

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

因此,在比较两个指针时,编译器实际上比较了转换的指针,它们是相等的.


luk*_*k32 8

我知道有一个答案,但也许这将更直接,并通过一个例子备份.

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

如果你使用这段代码:

#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;
    }
}
Run Code Online (Sandbox Code Playgroud)

你得到:

The address of b is 0x0x88f900c
The address of c is 0x0x88f9008
The address of (B*)c is 0x0x88f900c
b is equal to c
Run Code Online (Sandbox Code Playgroud)

所以c铸造到B*类型都有相同的地址b.正如所料.


Nob*_*lis 7

如果我可以添加迈克的优秀答案,如果你将它们投射,void*那么你将获得预期的行为:

if ((void*)(b) == (void*)(c))
    ^^^^^^^       ^^^^^^^
Run Code Online (Sandbox Code Playgroud)

版画

b is not equal to c
Run Code Online (Sandbox Code Playgroud)

由于比较的指针类型不同,在C(语言)上做类似的事情实际上激怒了编译器.

我有:

warning: comparison of distinct pointer types lacks a cast [enabled by default]
Run Code Online (Sandbox Code Playgroud)