포인터 값은 다르지만 동일하게 비교됩니다. 왜?
짧은 예제는 이상한 결과를 출력합니다!
#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 is equal to c"입니다.
C
개체 유형의 두 개의 서브 - 객체 포함 A
와 B
. 두 개의 개별 개체가 동일한 주소를 가질 수 없기 때문에 이러한 주소는 서로 다른 주소를 가져야합니다. 따라서 이들 중 최대 하나는 C
객체 와 동일한 주소를 가질 수 있습니다 . 그래서 포인터를 인쇄하면 다른 값이 제공됩니다.
포인터를 비교하는 것은 단순히 숫자 값을 비교하는 것이 아닙니다. 동일한 유형의 포인터 만 비교할 수 있으므로 첫 번째 포인터는 다른 포인터와 일치하도록 변환해야합니다. 이 경우 c
는 B*
. 이것은 b
처음 에 초기화하는 데 사용 된 것과 똑같은 변환입니다 . 포인터 값을 조정하여 B
개체가 아닌 하위 개체를 가리키고 C
이제 두 포인터가 동일하게 비교됩니다.
유형 객체의 메모리 레이아웃은 C
다음과 같습니다.
| <---- C ----> |
|-A: a-|-B: b-|- c -|
0 4 8 12
객체의 주소 (sizeof (int) = 4 인 플랫폼에서)의 오프셋을 바이트 단위로 추가했습니다.
메인에는 두 개의 포인터가 있습니다 . 명확성을 위해 이름을 pb
and pc
로 변경하겠습니다 . pc
전체 C 오브젝트 pb
의 시작 을 가리키고 B 하위 오브젝트의 시작 을 가리 킵니다.
| <---- C ----> |
|-A: a-|-B: b-|- c -|
0 4 8 12
pc-^ pb-^
이것이 그들의 가치가 다른 이유입니다. 3E9A98 + 4는 16 진수로 된 3E9A9C입니다.
이제이 두 포인터를 비교하면 컴파일러 는 다른 유형 인 a B*
와 a 간의 비교를 볼 수 C*
있습니다. 따라서 암시 적 변환이있는 경우 적용해야합니다. pb
로 변환 할 수는 없지만 C*
다른 방법으로 라운드가 가능 pc
합니다 B*
. 즉, . 이 변환은 가리키는 위치의 B 하위 개체를 가리키는 포인터를 제공합니다. 이는 pc
정의 할 때 사용한 것과 동일한 암시 적 변환 B* pb = pc;
입니다. 결과는 다음과 같습니다 pb
.
| <---- C ----> |
|-A: a-|-B: b-|- c -|
0 4 8 12
pc-^ pb-^
(B*)pc-^
따라서 두 포인터를 비교할 때 컴파일러는 실제로 동일한 변환 된 포인터를 비교합니다.
나는 답이 있다는 것을 알고 있지만 아마도 이것은 더 간단하고 예를 통해 뒷받침 될 것입니다.
There is an implicit conversion from C*
to B*
on c
operand in 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
casted to B*
type has the same address as b
. As expected.
If I may add to Mike's excellent answer, if you cast them as void*
then you will get your expected behaviour:
if ((void*)(b) == (void*)(c))
^^^^^^^ ^^^^^^^
prints
b is not equal to c
Doing something similar on C (the language) actually irritated the compiler due to the different types of the pointers compared.
I got:
warning: comparison of distinct pointer types lacks a cast [enabled by default]
In computing (or, rather, we should say in mathematics) there can be many notions of equality. Any relation that is symmetric, reflexive and transitive can be employed as equality.
In your program, you are examining two somewhat different notions of equality: bitwise implementation identity (two pointers being to exactly the same address) versus another kind of equality based on object identity, which allows two views on the same object, through references of different static type, to be properly regarded as referencing the same object.
These differently typed views use pointers which do not have the same address value, because they latch on to different parts of the object. The compiler knows this and so it generates the correct code for the equality comparison which takes into account this offset.
It is the structure of objects brought about by inheritance which makes it necessary to have these offsets. When there are multiple bases (thanks to multiple inheritance), only one of those bases can be at the low address of the object, so that the pointer to the base part is the same as the pointer to the derived object. The other base parts are elsewhere in the object.
So, naive, bitwise comparison of pointers would not yield the correct results according to the object-oriented view of the object.
Some good answers here, but there's a short version. "Two objects are the same" does not mean they have the same address. It means putting data into them and taking data out of them is equivalent.
참고URL : https://stackoverflow.com/questions/18272909/pointer-values-are-different-but-they-compare-equal-why
'Nice programing' 카테고리의 다른 글
NPOI를 사용하여 파일을 읽는 방법 (0) | 2020.10.28 |
---|---|
프로그래밍 방식으로 스토리 보드 ID를 얻습니까? (0) | 2020.10.28 |
Ansible : 현재 대상 호스트의 IP 주소 가져 오기 (0) | 2020.10.28 |
람다 미적분을 아는 것이 얼마나 도움이됩니까? (0) | 2020.10.28 |
디버거 란 무엇이며 문제를 진단하는 데 어떻게 도움이됩니까? (0) | 2020.10.27 |