Czy void * function () jest wskaźnikiem funkcji lub funkcja zwraca void *?

26

Jestem zdezorientowany co do znaczenia void *function().
Czy to wskaźnik do funkcji, czy funkcja powraca void*? Zawsze używałem go w strukturach danych jako funkcji rekurencyjnej zwracającej wskaźnik, ale kiedy zobaczyłem kod w wielowątkowości ( pthread), jest taka sama deklaracja funkcji. Teraz jestem zdezorientowany, jaka jest między nimi różnica.

użytkownik9515151
źródło
5
@goodvibration C został pozbawiony formatu (i C ++ „odziedziczył” to). Nawet void*function();jest poprawny pod względem składniowym. Na przykład dla Pythona wybrali inną decyzję - format jest częścią składni. IMHO, oba sposoby mają swoje zalety i wady.
Scheff,
3
@goodvibration im bardziej próbujesz chronić programistę przed robieniem tego, czego chcą, tym więcej dostajesz czegoś takiego jak java;)
idclev 463035818
2
@goodvibration Mniej opcji, mniej elastyczności. I proszę, pamiętajcie, że minęły dekady, kiedy to zrobili. Łatwo potem narzekać ... ;-)
Scheff
2
W języku C void *function()jest funkcją pobierającą dowolną liczbę argumentów i zwracającą wartość, która po dereferencji jest typu void . W C ++ void* function()jest funkcją, która nie przyjmuje argumentów i zwraca wartość wskaźnika do void . Powinieneś zdecydować, w którym języku pytasz.
Stephen M. Webb
1
@ StephenM.Webb Nie możnavoid * wyłuskać a . W końcu, nawet gdybyś mógł, co byś zrobił z void?
Fabio mówi Przywróć Monikę

Odpowiedzi:

38

Funkcja ma typ zwracany void *.

void *function();

Dlatego zawsze wolę w takich przypadkach oddzielić symbol *od nazwy funkcji, takiej jak

void * function();

I jak Jarod42wskazano w komentarzu, możesz przepisać deklarację funkcji w C ++, używając końcowego typu powrotu, takiego jak

auto function() -> void *;

Jeśli chcesz zadeklarować wskaźnik do działania, powinieneś napisać

void ( *function )();

Lub

void * ( *function )();

Lub wskaźnik do funkcji, który zwraca wskaźnik do funkcji

void * ( *( *function )() )();
Vlad z Moskwy
źródło
2
Dlatego wolę pisać void* function();. To nie jest takie kuszące ... ;-) (Edycja nastąpiła właśnie podczas pisania tego.)
Scheff
w kodzie deklaruję void * reader();następnie pthread_create(&thread1,null,reader,reader_arg)zamiastpthread_create(&thread1,null,&reader,reader_arg)
user9515151
1
@Scheff: Lub nawet auto function() -> void*(C ++). :)
Jarod42
3
Lub wskaźnik do funkcji, który zwraca wskaźnik do funkcji To jest to, co typedefjest ... ;-)
Andrew Henle,
1
@AndrewHenle Z typedef nie ma problemu. Problem pojawia się, gdy deklaracje są używane bez deklaracji typedef lub aliasu. :)
Vlad z Moskwy
7

Ilekroć nie mam pewności co do problemów ze składnią języka C, lubię używać narzędzia cdecl ( wersja online ) do interpretowania mnie. To tłumaczy między składnią C i angielskim.

Na przykład podaję twój przykład void *foo()i on zwrócił

zadeklaruj foo jako funkcję zwracającą wskaźnik do void

Aby zobaczyć, jak wyglądałaby druga składnia, wpisałem declare foo as pointer to function returning voidi wróciłem

void (* foo) ()

Jest to szczególnie przydatne, gdy w jednym wyrażeniu jest wiele poziomów rzutów czcionek, gwiazd lub nawiasów.

bta
źródło
2

Jest to funkcja zwracająca wskaźnik do void.

Pomyśl o swojej deklaracji w ten sposób:

void *(function());

Byłaby to funkcja zwracająca void(lub nic):

void (*function2)();

Pomyśl o powyższej deklaracji w ten sposób:

void ((*function2)());

Znacznie łatwiejszym sposobem napisania jest użycie typedefs:

typedef void *function_returning_void_pointer();
typedef void function_returning_nothing();

function_returning_void_pointer function;
function_returning_nothing *function2;

To ogólnie eliminuje zamieszanie wokół wskaźników funkcji i jest znacznie łatwiejsze do odczytania.

SS Anne
źródło
0

Deklaracje w C / C ++ są odczytywane z identyfikatora na zewnątrz zgodnie z pierwszeństwem operatora .

Szybkie spojrzenie na tabelę pierwszeństwa operatora C / C ++ na wikipedii pokazuje, że operator wywołania funkcji ()ma wyższy priorytet niż operator pośredni *. Tak więc deklaracje funkcji brzmią następująco:

  • Zacznij od identyfikatora: functionis

  • function() funkcja, która nie przyjmuje argumentów

  • void* function()i zwraca a void*.

Ta ogólna zasada obowiązuje również w przypadku deklaracji tablicowych ( []ma również wyższy priorytet niż *) i kombinacji tych dwóch. Więc

int *(*arr[42])();

jest czytany jako

  • arr jest
  • arr[42] tablica 42 elementów, które są
  • *arr[42] wskaźniki do
  • (*arr[42])() funkcje, które nie przyjmują argumentów i
  • int *(*arr[42])()zwracać int*.

Przyzwyczajenie się do tego zajmuje trochę czasu, ale po zrozumieniu zasady łatwo jest jednoznacznie odczytać te deklaracje.

cmaster - przywróć monikę
źródło