C - funkcja wewnątrz struktury


86

Próbuję stworzyć funkcję wewnątrz struktury, do tej pory mam taki kod:

Błąd : klient.h: 24: 2: błąd: oczekiwano „:”, „,”, „;”, „}” lub „ atrybut ” przed tokenem „{”.

Jaki jest właściwy sposób, aby to zrobić?


12
Nie możesz mieć funkcji w strukturach w C; możesz jednak spróbować z grubsza to zasymulować za pomocą wskaźników funkcji.
Fingolfin

1
Czy wskaźniki funkcji są akceptowalnym substytutem? stackoverflow.com/a/840703/635678
Dan O,

Odpowiedzi:


108

Nie można tego zrobić bezpośrednio, ale można emulować to samo, używając wskaźników do funkcji i jawnie przekazując parametr „this”:

Okazuje się, że robienie tego nie kupuje jednak zbyt wiele. W związku z tym nie zobaczysz wielu interfejsów API C zaimplementowanych w tym stylu, ponieważ równie dobrze możesz po prostu wywołać swoją funkcję zewnętrzną i przekazać instancję.


3
X11 API robi coś takiego. Zobacz XImage .
Hydranix,

1
kod, który znajduje się pod Windows API, jest tego pełen. Z technicznego punktu widzenia „klasa okna” jest strukturą z dwoma wskaźnikami funkcji wywołania zwrotnego i otwartym końcem (dla tych „danych specyficznych dla klasy okna” można podać podczas rejestracji)
Swift - Friday Pie

1
wykonałem te kroki, ale kiedy zrobię struct.function = newFunction, kompilator wypisze: error: oczekiwano '=', ',', ';', 'asm' lub ' atrybut ' przed '.' żeton
Bonfra

Byłoby to również przydatne, gdy chciałbyś mieć wspólny cel (np. Dysk twardy), który ma funkcję odczytu i zapisu, ale który różni się od jednego typu dysku twardego do nexf
Menotdan

Może cię dużo kupić, jeśli rzeczywista implementacja zostanie wybrana w czasie wykonywania. Jeśli masz tylko funkcję statyczną, zawsze musisz ponownie wybrać w ramach tej funkcji przy każdym wywołaniu funkcji, jeśli używasz wskaźnika funkcji, zaznaczenie nastąpi tylko raz. A wybór może się zmieniać nawet przez cały okres istnienia struktury.
Mecki

24

Jak zauważyli inni, osadzanie wskaźników funkcji bezpośrednio wewnątrz struktury jest zwykle zarezerwowane do specjalnych celów, takich jak funkcja wywołania zwrotnego.

To, czego prawdopodobnie potrzebujesz, to coś w rodzaju wirtualnej tabeli metod.

Teraz dodanie większej liczby operacji nie zmienia rozmiaru client_tstruktury. Ten rodzaj elastyczności jest przydatny tylko wtedy, gdy musisz zdefiniować wiele rodzajów klientów lub chcesz umożliwić użytkownikom client_tinterfejsu rozszerzenie sposobu, w jaki zachowują się operacje.

Taka struktura pojawia się w prawdziwym kodzie. Warstwa OpenSSL BIO wygląda podobnie, a także interfejsy sterowników urządzeń UNIX mają taką warstwę.


15

To zadziała tylko w C ++. Funkcje w strukturach nie są cechą C.

To samo dotyczy twojego klienta.AddClient (); call ... to jest wywołanie funkcji składowej, która jest programowaniem obiektowym, tj. C ++.

Przekonwertuj źródło na plik .cpp i upewnij się, że odpowiednio kompilujesz.

Jeśli chcesz trzymać się C, poniższy kod jest (w pewnym sensie) odpowiednikiem:


1
To jest projekt uni i muszę używać C. Czy jest jakiś sposób, żebym mógł wykonać to, co chcę w C?
xRed,

Po prostu przenieś tę funkcję poza strukturę i spraw, by akceptowała wskaźnik do Twojej instancji.
user123

Sprawa client.AddClient () nie byłaby możliwa bez odrobiny skomplikowanej magii (patrz druga odpowiedź).
QSQ

14

Co powiesz na to?


"Trochę" rozwiązanie podobne do JavaScriptu
Bitman

8

Próbujesz zgrupować kod według struktury. Grupowanie w C odbywa się według pliku. Umieszczasz wszystkie funkcje i zmienne wewnętrzne w nagłówku lub nagłówku i pliku obiektu „.o” skompilowanym z pliku źródłowego ac.

Nie ma potrzeby odkrywania na nowo orientacji obiektowej od podstaw dla programu C, który nie jest językiem zorientowanym obiektowo.

Widziałem to już wcześniej. To dziwna rzecz. Niektórzy z nich mają niechęć do przekazywania obiektu, który chcą zmienić, w funkcję, która go zmieni, nawet jeśli jest to standardowy sposób.

Obwiniam C ++, ponieważ ukrywało to, że obiekt klasy jest zawsze pierwszym parametrem w funkcji składowej, ale jest ukryty. Wygląda więc na to, że nie przekazuje obiektu do funkcji, mimo że tak jest.

C jest elastyczny i może przyjmować przekazywanie rzeczy przez odniesienie.

Funkcja AC często zwraca tylko bajt stanu lub int i często jest to ignorowane. W twoim przypadku może być odpowiednia forma

addClient byłby w Client.h lub Client.c


Takie podejście ma swoje wady i zalety. To, że zawsze tak było , odnosząc się zarówno do strategii non-OO ( do(object, subject)), jak i OO ( subject.do(object)), nie oznacza, że ​​powinniśmy przestać próbować. Całkowicie uważam, że słuszne jest wskazanie, że to nie jest historyczny sposób, w jaki napisano C, i że C nie musi być pisane w ten sposób (to samo dotyczy wielu języków, zwłaszcza paradygmatów proceduralnych, funkcjonalnych lub logicznych) ale nie musimy aktywnie zniechęcać do wzorca. Ma to również pewne zalety
hiljusti

0

Możesz przekazać wskaźnik struct, aby działał jako argument funkcji. Nazywało się to przekazywaniem przez odniesienie.

Jeśli zmodyfikujesz coś wewnątrz tego wskaźnika, inne zostaną zaktualizowane do. Spróbuj tak:


Nie ma przejścia przez referencję C. Przekazujesz kopię wskaźnika, referencje wskaźnika są takie same, ale same wskaźniki nie.
Sierżant Cortez,

Dziękuję za korektę. Przeczytałem C pass przez poradnik referencyjny z Tutorialspoint. Czy to się różni od tego, co napisałem powyżej?
Hadi Hidayat Hammurabi
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.