Załóżmy, że mam 2 wskazówki:
int *a = something;
int *b = something;
Jeśli chcę je porównać i sprawdzić, czy wskazują na to samo miejsce, czy (a == b) działa?
Załóżmy, że mam 2 wskazówki:
int *a = something;
int *b = something;
Jeśli chcę je porównać i sprawdzić, czy wskazują na to samo miejsce, czy (a == b) działa?
Odpowiedzi:
Tak, to jest definicja równości wskaźników: oba wskazują tę samą lokalizację (lub są aliasami wskaźników )
Po trochę faktów tutaj jest odpowiedni tekst specyfikacji
Wskaźniki do obiektów tego samego typu można porównać pod kątem równości z „intuicyjnymi” oczekiwanymi wynikami:
Od § 5.10 standardu C ++ 11:
Wskaźniki tego samego typu (po konwersji wskaźnika) można porównać pod kątem równości. Dwa wskaźniki tego samego typu porównują się równo wtedy i tylko wtedy, gdy oba mają wartość null, oba wskazują na tę samą funkcję lub oba reprezentują ten sam adres ( 3.9.2 ).
(pomijając szczegóły dotyczące porównania wskaźników do składowych i / lub stałych wskaźników zerowych - kontynuują one w tym samym wierszu „Zrób to, co mam na myśli” :)
- [...] Jeśli oba operandy są zerowe, porównują równe. W przeciwnym razie, jeśli tylko jeden jest zerowy, porównują nierówności. [...]
Najbardziej `` rzucające się w oczy '' zastrzeżenie dotyczy wirtualiów i wydaje się, że jest to również logiczne zastrzeżenie:
- [...] jeśli którykolwiek z nich jest wskaźnikiem do wirtualnej funkcji składowej, wynik jest nieokreślony. W przeciwnym razie porównują równe wtedy i tylko wtedy, gdy odnoszą się do tego samego elementu członkowskiego tego samego najbardziej pochodnego obiektu (1.8) lub do tego samego podobiektu, gdyby zostały wyłuskane z hipotetycznym obiektem skojarzonego typu klasy. […]
Od § 5.9 standardu C ++ 11:
Wskaźniki do obiektów lub funkcji tego samego typu (po konwersji wskaźnika) można porównać, uzyskując wynik zdefiniowany w następujący sposób:
- Jeśli dwa wskaźniki p i q tego samego typu wskazują na ten sam obiekt lub funkcję, lub oba wskazują jeden za koniec tej samej tablicy lub oba mają wartość null, to
p<=q
ip>=q
oba dają wartość truep<q
ip>q
obie dają false.- Jeśli dwa wskaźniki p i q tego samego typu wskazują na różne obiekty, które nie są elementami składowymi tego samego obiektu lub elementów tej samej tablicy lub różnych funkcji, lub jeśli tylko jeden z nich jest pusty, wyniki operacji
p<q,
p>q,
p<=q,
ip>=q
są nieokreślone .- Jeśli dwa wskaźniki wskazują na niestatyczne elementy składowe danych tego samego obiektu lub podobiekty lub elementy tablicy takich elementów członkowskich, rekurencyjnie, wskaźnik do później zadeklarowanego elementu członkowskiego jest większy, pod warunkiem, że dwa elementy członkowskie mają tę samą kontrolę dostępu (klauzula 11) i pod warunkiem, że ich klasa nie jest związkiem.
- Jeśli dwa wskaźniki wskazują na niestatyczne elementy składowe danych tego samego obiektu z różną kontrolą dostępu (klauzula 11), wynik jest nieokreślony.
- Jeśli dwa wskaźniki wskazują na niestatyczne elementy składowe danych tego samego obiektu unii, porównują się równo (po konwersji
void*
, jeśli to konieczne). Jeśli dwa wskaźniki wskazują na elementy tej samej tablicy lub jeden za końcem tablicy, wskaźnik do obiektu z wyższym indeksem jest wyższy.- Inne porównania wskaźników są nieokreślone.
Tak więc, gdybyś miał:
int arr[3];
int *a = arr;
int *b = a + 1;
assert(a != b); // OK! well defined
Też dobrze:
struct X { int x,y; } s;
int *a = &s.x;
int *b = &s.y;
assert(b > a); // OK! well defined
Ale to zależy od something
pytania:
int g;
int main()
{
int h;
int i;
int *a = &g;
int *b = &h; // can't compare a <=> b
int *c = &i; // can't compare b <=> c, or a <=> c etc.
// but a==b, b!=c, a!=c etc. are supported just fine
}
§ 20.8.5 / 8 : „W przypadku szablonów greater
, less
, greater_equal
oraz less_equal
, że specjalizacje dla każdego rodzaju wskaźnik uzyskując całkowitą zamówienia, nawet jeśli wbudowany operatorów <
, >
, <=
, >=
nie.”
Możesz więc zamówić dowolne nieparzyste void*
na całym świecie , o ile używasz std::less<>
i przyjaciół, a nie gołych operator<
.
int *a = arr;
wiersz skorzystałby na dołączeniu odwołania do stackoverflow.com/questions/8412694/address-of-array ? Nie jestem pewien, czy jest to wystarczające do zadanego pytania ...
<functional>
. Dodany.
==
Operator na wskaźnikach będzie porównać swój adres numeryczny, a więc ustalić, czy wskazują one na tym samym obiekcie.
Podsumowując. Jeśli chcemy zobaczyć, czy dwa wskaźniki wskazują na tę samą lokalizację pamięci, możemy to zrobić. Również jeśli chcemy porównać zawartość pamięci wskazywaną przez dwa wskaźniki, możemy to również zrobić, po prostu pamiętajmy, aby najpierw je wyodrębnić.
Jeśli mamy
int *a = something;
int *b = something;
które są dwoma wskaźnikami tego samego typu, możemy:
Porównaj adres pamięci:
a==b
i porównaj zawartość:
*a==*b
Prosty kod do sprawdzania aliasingu wskaźnika:
int main () {
int a = 10, b = 20;
int *p1, *p2, *p3, *p4;
p1 = &a;
p2 = &a;
if(p1 == p2){
std::cout<<"p1 and p2 alias each other"<<std::endl;
}
else{
std::cout<<"p1 and p2 do not alias each other"<<std::endl;
}
//------------------------
p3 = &a;
p4 = &b;
if(p3 == p4){
std::cout<<"p3 and p4 alias each other"<<std::endl;
}
else{
std::cout<<"p3 and p4 do not alias each other"<<std::endl;
}
return 0;
}
Wynik:
p1 and p2 alias each other
p3 and p4 do not alias each other
Porównywanie wskaźników nie jest przenośne, na przykład w DOS różne wartości wskaźników wskazują na tę samą lokalizację, porównanie wskaźników zwraca fałsz.
/*--{++:main.c}--------------------------------------------------*/
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int val_a = 123;
int * ptr_0 = &val_a;
int * ptr_1 = MK_FP(FP_SEG(&val_a) + 1, FP_OFF(&val_a) - 16);
printf(" val_a = %d -> @%p\n", val_a, (void *)(&val_a));
printf("*ptr_0 = %d -> @%p\n", *ptr_0, (void *)ptr_0);
printf("*ptr_1 = %d -> @%p\n", *ptr_1, (void *)ptr_1);
/* Check what returns the pointers comparison: */
printf("&val_a == ptr_0 ====> %d\n", &val_a == ptr_0);
printf("&val_a == ptr_1 ====> %d\n", &val_a == ptr_1);
printf(" ptr_0 == ptr_1 ====> %d\n", ptr_0 == ptr_1);
printf("val_a = %d\n", val_a);
printf(">> *ptr_0 += 100;\n");
*ptr_0 += 100;
printf("val_a = %d\n", val_a);
printf(">> *ptr_1 += 500;\n");
*ptr_1 += 500;
printf("val_a = %d\n", val_a);
return EXIT_SUCCESS;
}
/*--{--:main.c}--------------------------------------------------*/
Skompiluj go pod Borland C 5.0, oto wynik:
/*--{++:result}--------------------------------------------------*/
val_a = 123 -> @167A:0FFE
*ptr_0 = 123 -> @167A:0FFE
*ptr_1 = 123 -> @167B:0FEE
&val_a == ptr_0 ====> 1
&val_a == ptr_1 ====> 0
ptr_0 == ptr_1 ====> 0
val_a = 123
>> *ptr_0 += 100;
val_a = 223
>> *ptr_1 += 500;
val_a = 723
/*--{--:result}--------------------------------------------------*/