Dlaczego definicje wskaźników funkcji działają z dowolną liczbą ampersandów ' & 'LUB GWIAZDEK'*'?

Dlaczego wykonujesz następującą pracę?

void foo() {
    cout << "Foo to you too!\n";
};

int main() {
    void (*p1_foo)() = foo;
    void (*p2_foo)() = *foo;
    void (*p3_foo)() = &foo;
    void (*p4_foo)() = *&foo;
    void (*p5_foo)() = &*foo;
    void (*p6_foo)() = **foo;
    void (*p7_foo)() = **********************foo;

    (*p1_foo)();
    (*p2_foo)();
    (*p3_foo)();
    (*p4_foo)();
    (*p5_foo)();
    (*p6_foo)();
    (*p7_foo)();
}
Author: Lundin, 2011-08-01

3 answers

Istnieje kilka elementów, które pozwalają wszystkim tym kombinacjom operatorów działać w ten sam sposób.

Podstawową przyczyną tego działania jest to, że funkcja (jak foo) jest w domyśle zamieniana na wskaźnik do funkcji. Dlatego void (*p1_foo)() = foo; działa: {[0] } jest niejawnie zamieniany na wskaźnik do siebie i ten wskaźnik jest przypisany do p1_foo.

Unary &, gdy zostanie zastosowana do funkcji, daje wskaźnik do funkcji, tak jak daje adres obiektu, gdy jest on zastosowany do obiektu. W przypadku wskaźników do zwykłych funkcji, jest on zawsze redundantny ze względu na niejawną konwersję funkcji do funkcji wskaźnika. W każdym razie, to dlatego void (*p3_foo)() = &foo; działa.

Uniary *, gdy zostanie zastosowany do wskaźnika funkcji, daje funkcję wskazywaną do, podobnie jak daje wskazywaną do obiektu, gdy zostanie zastosowany do zwykłego wskaźnika do obiektu.

Te zasady można łączyć. Rozważ swój przedostatni przykład, **foo:

  • pierwszy, {[0] } jest implicite konwertowany na wskaźnik do siebie, a pierwszy * jest stosowany do tego wskaźnika funkcji, dając funkcję foo ponownie.
  • następnie wynik jest ponownie implicite zamieniany na wskaźnik do siebie i drugi * jest stosowany, ponownie dając funkcję foo.
  • jest on następnie domyślnie zamieniany na wskaźnik funkcji i przypisywany do zmiennej.

Możesz dodać tyle * s ile chcesz, wynik jest zawsze taki sam. Im więcej *s, tym weselej.

Możemy również rozważyć Twój piąty przykład, &*foo:

  • Po pierwsze, foo jest implicite konwertowany do wskaźnika do siebie; jednoargumentowy * jest stosowany, dając foo ponownie.
  • następnie, & jest stosowany do foo, dając wskaźnik do foo, który jest przypisany do zmiennej.

The & może być stosowany tylko do funkcji, ale nie do funkcji, która została przekonwertowana na wskaźnik funkcji (o ile, oczywiście, wskaźnik funkcji nie jest zmienną, w takim przypadku wynikiem jest wskaźnik-do-wskaźnika-do-funkcji; na przykład, można dodać do listy void (**pp_foo)() = &p7_foo;).

Dlatego &&foo nie działa: &foo nie jest funkcją; jest wskaźnikiem funkcji, który jest wartością r. Jednak &*&*&*&*&*&*foo będzie działać, podobnie jak &******&foo, ponieważ w obu tych wyrażeniach & jest zawsze stosowany do funkcji, a nie do wskaźnika funkcji rvalue.

Zauważ również, że nie musisz należy użyć uniary * do wywołania za pomocą wskaźnika funkcji; zarówno (*p1_foo)();, jak i (p1_foo)(); mają ten sam wynik, ponownie ze względu na konwersję funkcji na wskaźnik.

 228
Author: James McNellis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-19 16:33:05

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 punktu widzenia komputera, funkcja jest tylko adresem pamięci, który, jeśli zostanie wykonany, wykonuje inne instrukcje. Tak więc funkcja w C sama jest modelowana jako adres, co prawdopodobnie prowadzi do projektu, że funkcja jest "taka sama" jak adres, na który wskazuje.

 12
Author: madumlao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-09 04:58:07

& i * są idempotentnymi operacjami na symbolu zadeklarowanym jako funkcja w C, co oznacza func == *func == &func == *&func i dlatego *func == **func

Oznacza to, że typ int () jest taki sam jak int (*)() jako parametr funkcji i zdefiniowany func może być przekazany jako *func, func lub &func. (&func)() jest tym samym co func(). [[19]}Godbolt link.

Funkcja jest rzeczywiście adresem, dlatego * i & nie mają znaczenia i zamiast generować błąd, kompilator decyduje się zinterpretować go jako adres func.

& Na symbolu zadeklarowanym jako wskaźnik funkcji jednak otrzyma adres wskaźnika (ponieważ teraz ma osobny cel), podczas gdy funcp i *funcp będą identyczne

 0
Author: Lewis Kelsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-29 22:23:57