2013-06-11 17 views
49

Im próbuje utworzyć funkcję wewnątrz struktury, do tej pory mam tego kodu:C - funkcja wewnątrz struktury

typedef struct client_t client_t, *pno; 
struct client_t 
{ 
     pid_t pid; 
     char password[TAM_MAX]; // -> 50 chars 
     pno next; 

     pno AddClient() 

     { 
      /* code */ 
     } 

}; 

int main() 
{ 

    client_t client; 

    //code .. 

    client.AddClient(); 

} 

błąd: client.h: 24: 2: błąd: oczekiwano „: Atrybut ",", ",", ","} "lub" "" before "{'token.

Który jest poprawny sposób to zrobić?

+9

Nie można mieć funkcje w elemencie w C; możesz spróbować z grubsza zasymulować to za pomocą wskaźników funkcji. – Fingolfin

+1

Czy wskaźniki funkcji są akceptowalnym zamiennikiem? http://stackoverflow.com/a/840703/635678 –

Odpowiedz

71

Nie można zrobić bezpośrednio, ale można naśladować to samo przy użyciu wskaźników funkcji i wyraźnie przechodząc „to” parametr:

typedef struct client_t client_t, *pno; 
struct client_t 
{ 
     pid_t pid; 
     char password[TAM_MAX]; // -> 50 chars 
     pno next; 

     pno (*AddClient)(client_t *);  
}; 

pno client_t_AddClient(client_t *self) { /* code */ } 

int main() 
{ 

    client_t client; 
    client.AddClient = client_t_AddClient; // probably really done in some init fn 

    //code .. 

    client.AddClient(&client); 

} 

okazuje się, że robi to jednak naprawdę nie kupić ci bardzo dużo. W związku z tym nie zobaczysz wielu API C zaimplementowanych w tym stylu, ponieważ równie dobrze możesz po prostu wywołać swoją zewnętrzną funkcję i przekazać instancję.

+1

Wielkie dzięki, sir – amanuel2

+1

Interfejs API X11 robi coś takiego. Zobacz [XImage] (https://en.wikipedia.org/wiki/XImage). Kod – Hydranix

+0

, który leży pod interfejsem API systemu Windows, jest pełen tego kodu. Z technicznego punktu widzenia "klasą okien" jest struktura z dwoma wskaźnikami funkcji wywołania zwrotnego iz otwartym końcem (dla tych "danych specyficznych dla klasy okna", które można podać podczas rejestracji). – Swift

10

To będzie działać tylko w C++. Funkcje w strukturach nie są cechą C

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

Konwersja źródła do pliku .cpp i upewnij się, że są odpowiednio kompilacji.

Jeśli trzeba trzymać się C, poniżej kod jest (w pewnym sensie) równowartość:

typedef struct client_t client_t, *pno; 
struct client_t 
{ 
     pid_t pid; 
     char password[TAM_MAX]; // -> 50 chars 
     pno next; 

}; 


pno AddClient(pno *pclient) 
{ 
    /* code */ 
} 


int main() 
{ 

    client_t client; 

    //code .. 

    AddClient(client); 

} 
+0

To jest projekt uni i muszę użyć C. Czy jest jakiś sposób mogę osiągnąć to, czego chcę w C? – xRed

+0

Po prostu przenieś tę funkcję poza strukturę i ustaw ją jako akceptującą wskaźnik do instancji. –

+0

Funkcja client.AddClient() nie będzie możliwa bez odrobiny skomplikowanej magii (zobacz drugą odpowiedź). – QSQ

18

jak inni to zauważyli, osadzanie wskaźników funkcji bezpośrednio wewnątrz swojej struktury jest zazwyczaj zarezerwowane dla specjalnych celów, jak funkcję zwrotną.

Co prawdopodobnie chcesz coś bardziej wirtualnym stole metody.

typedef struct client_ops_t client_ops_t; 
typedef struct client_t client_t, *pno; 

struct client_t { 
    /* ... */ 
    client_ops_t *ops; 
}; 

struct client_ops_t { 
    pno (*AddClient)(client_t *); 
    pno (*RemoveClient)(client_t *); 
}; 

pno AddClient (client_t *client) { return client->ops->AddClient(client); } 
pno RemoveClient (client_t *client) { return client->ops->RemoveClient(client); } 

Teraz, dodając więcej operacji nie zmienia rozmiar struktury client_t. Ten rodzaj elastyczności jest przydatny tylko wtedy, gdy musisz zdefiniować wiele rodzajów klientów lub chcesz umożliwić użytkownikom Twojego interfejsu client_t, aby zwiększyć jego działanie.

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

+0

Zobacz także [dynamiczna wysyłka] (http://stackoverflow.com/a/17622474/315052). – jxh

4

Co powiesz na to?

#include <stdio.h> 

typedef struct hello { 
    int (*someFunction)(); 
} hello; 

int foo() { 
    return 0; 
} 

hello Hello() { 
    struct hello aHello; 
    aHello.someFunction = &foo; 
    return aHello; 
} 

int main() 
{ 
    struct hello aHello = Hello(); 
    printf("Print hello: %d\n", aHello.someFunction()); 

    return 0; 
} 
+0

"Małe" rozwiązanie typu JavaScrip –

0

Próbujesz zgrupować kod według struct. Grupowanie C odbywa się według pliku. Wszystkie funkcje i zmienne wewnętrzne w nagłówku lub umieszczasz w nagłówku i pliku ".o" obiektu skompilowanym z pliku źródłowego c.

Nie jest konieczne odświeżanie obiektowej orientacji od zera dla programu C, który nie jest językiem zorientowanym obiektowo.

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

Obwiniam C++, ponieważ ukrył fakt, ż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 jest.

Client.addClient(Client& c); // addClient first parameter is actually 
          // "this", a pointer to the Client object. 

C jest elastyczny i może przyjmować przekazywanie przedmiotów przez odniesienie.

Funkcja C często zwraca tylko bajt statusu lub int i często jest ignorowana. W twoim przypadku właściwa forma może być

err = addClient(container_t cnt, client_t c); 
if (err != 0) 
    { fprintf(stderr, "could not add client (%d) \n", err); 

addclient byłoby Client.h lub Client.c