Jest w tym kilka elementów, które pozwalają wszystkim kombinacjom operatorów działać w ten sam sposób.
Podstawowym powodem, dla którego wszystkie z tych działań jest to, że funkcja (podobna foo
) jest domyślnie konwertowalna na wskaźnik do funkcji. Właśnie dlatego void (*p1_foo)() = foo;
działa: foo
jest domyślnie konwertowany na wskaźnik do siebie i ten wskaźnik jest przypisany p1_foo
.
Jednoargumentowy &
, po zastosowaniu do funkcji, daje wskaźnik do funkcji, podobnie jak podaje adres obiektu, gdy zostanie zastosowany do obiektu. W przypadku wskaźników do zwykłych funkcji zawsze jest redundantny z powodu niejawnej konwersji funkcji na wskaźnik funkcji. W każdym razie właśnie dlatego void (*p3_foo)() = &foo;
działa.
Jednoargumentowy *
, po zastosowaniu do wskaźnika funkcji, daje funkcję wskazaną do, podobnie jak daje obiekt wskazany, gdy jest stosowany do zwykłego wskaźnika do obiektu.
Reguły te można łączyć. Rozważ swój przykład od drugiego do ostatniego **foo
:
- Po pierwsze,
foo
jest domyślnie konwertowany na wskaźnik do siebie, a pierwszy *
jest stosowany do tego wskaźnika funkcji, dając foo
ponownie funkcję .
- Następnie wynik jest ponownie domyślnie konwertowany na wskaźnik do siebie, a drugi
*
jest stosowany, ponownie dając funkcję foo
.
- Następnie jest ponownie domyślnie konwertowany na wskaźnik funkcji i przypisywany do zmiennej.
Możesz dodać dowolną liczbę *
s, wynik jest zawsze taki sam. Im więcej *
s, tym lepiej.
Możemy również rozważyć Twój piąty przykład &*foo
:
- Po pierwsze,
foo
jest domyślnie konwertowany na wskaźnik do siebie; jednoargumentowy *
jest stosowany, ustępując foo
ponownie.
- Następnie
&
stosuje się do foo
, uzyskując wskaźnik do foo
, który jest przypisany do zmiennej.
&
Mogą być stosowane tylko do funkcji chociaż nie do funkcji, które zostały zamienione na wskaźnik funkcyjnych (o ile, oczywiście, wskaźnik funkcji jest zmienna, przy czym wynik jest wskaźnik do a-pointer- do funkcji; na przykład możesz dodać do swojej listy void (**pp_foo)() = &p7_foo;
).
Oto dlaczego &&foo
nie działa: &foo
nie jest funkcją; jest wskaźnikiem funkcji, który jest wartością. Jednak &*&*&*&*&*&*foo
działałoby to tak , jakby działało, &******&foo
ponieważ w obu tych wyrażeniach &
zawsze jest stosowane do funkcji, a nie do wskaźnika funkcji wartości.
Zauważ też, że nie trzeba używać unarnego, *
aby wykonać połączenie za pomocą wskaźnika funkcji; oba (*p1_foo)();
i (p1_foo)();
mają ten sam wynik, ponownie z powodu konwersji funkcji na wskaźnik funkcji.
&foo
przyjmuje adresfoo
, co powoduje, że wskaźnik funkcji wskazuje nafoo
, jak można by się spodziewać.&
operatorów dla obiektów: daneint p;
,&p
zwraca wskaźnik dop
i jest wyrażeniem wartości;&
operatora wymaga lwartością ekspresji.*
, tym mniej wesoło .&*
wzajemnego znoszenia się (6.5.3.2):"The unary & operator yields the address of its operand."
/ - /"If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue."
.Myślę, że warto również pamiętać, że C jest tylko abstrakcją dla podstawowej maszyny i jest to jedno z miejsc, w których ta abstrakcja przecieka.
Z perspektywy komputera funkcja jest tylko adresem pamięci, który, jeśli zostanie wykonany, wykonuje inne instrukcje. Tak więc funkcja w C jest sama modelowana jako adres, co prawdopodobnie prowadzi do projektu, że funkcja jest „taka sama” jak adres, na który wskazuje.
źródło
&
i*
są idempotencjalnymi operacjami na symbolu zadeklarowanym jako funkcja w C, co oznaczafunc == *func == &func == *&func
i dlatego*func == **func
Oznacza to, że typ
int ()
jest taki sam jakint (*)()
parametr funkcji, a zdefiniowaną funkcję można przekazać jako*func
,func
lub&func
.(&func)()
jest taki sam jakfunc()
. Link Godbolt.Dlatego funkcja jest naprawdę adresem
*
i&
nie ma żadnego znaczenia, a zamiast generowania błędu kompilator decyduje się interpretować go jako adres func.&
na symbolu zadeklarowanym jako wskaźnik funkcji uzyska jednak adres wskaźnika (ponieważ ma on teraz odrębny cel),funcp
a jednocześnie*funcp
będzie identycznyźródło