The pointer values ​​are different, but they are compared equal. What for?

A brief example displays a strange result!

#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; } } 

I am very surprised that the conclusion should be as follows:

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

Which makes me wonder:

0x003E9A9C is not equal to 0x003E9A98, but the output of "b is equal to c"

+69
c ++ pointers multiple-inheritance
Aug 16 '13 at 12:03
source share
6 answers

Object A C contains two sub-objects of type A and B Obviously, they must have different addresses, since two separate objects cannot have the same address; therefore, at most one of them can have the same address as object C This is why printing pointers gives different meanings.

Comparing pointers doesn't just compare their numerical values. You can only compare pointers of the same type, so you first need to convert them to match with each other. In this case, C converted to B* . This is the same transformation that is used to initialize B in the first place: it adjusts the value of the pointer so that it points to a sub-object of B and not to the object of C , and the two pointers are now compared equal.

+85
Aug 16 '13 at 12:12
source share

The memory layout of an object of type C will look something like this:

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

I added the offset in bytes from the Address of the object (on a platform like yours, with sizeof (int) = 4).

Basically, you have two pointers, I will rename them to pb and pc for clarity. pc points to the beginning of the entire object C, and pb points to the beginning of the subobject B:

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

That is why their meanings are different. 3E9A98 + 4 - 3E9A9C, in hex.

If you compare these two pointers, the compiler will see a comparison between B* and a C* , which are different types. Therefore, he must apply the implicit conversion, if any. pb cannot be converted to C* , but the return path is possible - it converts pc to B* . This conversion will give a pointer pointing to the subobject B where pc pointing out - this is the same implicit conversion that is used when defining B* pb = pc; . The result is pb , obviously:

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

Therefore, when comparing two pointers, the compiler actually compares the converted pointers equal.

+72
Aug 16 '13 at 12:21
source share

I know that there is an answer, but perhaps this will be a simpler and more supported example.

There is an implicit conversion from C* to B* to operand c here if (b == c)

If you go with this code:

 #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; } } 

You get:

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

So c dropped to type B* has the same address as b . As expected.

+8
Aug 16 '13 at 12:22
source share

If I can add an excellent answer to Mike, if you add them as void* , then you will get the expected behavior:

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

prints

 b is not equal to c 

Doing something like this in C (language) actually annoyed the compiler due to comparing different types of pointers.

I got:

 warning: comparison of distinct pointer types lacks a cast [enabled by default] 
+6
Aug 16 '13 at 12:18
source share

In computing (or rather, we should say in mathematics) there can be many concepts of equality. Any relation that is symmetric, reflexive, and transitive can be used as equality.

In your program, you learn two slightly different concepts of equality: the bitwise identity of the implementation (two pointers are at the same address) compared to another kind of equality based on the identity of an object that allows two representations on the same object, via links to different static types that should be considered as references to the same object.

These differently typed representations use pointers that do not have the same address value, because they are fixed on different parts of the object. The compiler is aware of this and therefore generates the correct code for comparing equality that takes this offset into account.

This is the structure of objects caused by inheritance, which makes these offsets necessary. When there are several reasons (due to multiple inheritance), only one of these bases can be at the low address of the object, so that the pointer to the base part matches the pointer to the derived object. Other base parts are located elsewhere in the facility.

Thus, a naive, bitwise comparison of pointers will not give the correct results in accordance with the object-oriented representation of the object.

+2
Aug 16 '13 at 19:00
source share

Some good answers here, but there is a short version. β€œTwo objects are the same” does not mean that they have the same address. This means that data is placed in them, and the data from them is equivalent.

+1
Aug 22 '13 at 20:15
source share



All Articles