118 votes

C - fonction dans une structure

J'essaie d'assigner une fonction à l'intérieur d'un struct Pour l'instant, j'ai ce code :

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();
}
**Error**: *client.h:24:2: error: expected ‘:’, ‘,’, ‘;’, ‘}’ or ‘__attribute__’ before ‘{’ token.*

Quelle est la bonne façon de procéder ?

144voto

FatalError Points 19772

Ce n'est pas possible de le faire directement, mais vous pouvez émuler la même chose en utilisant des pointeurs de fonction et en passant explicitement le paramètre "this" :

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);

}

Il s'avère toutefois que cette façon de faire ne vous apporte pas grand-chose. Ainsi, vous ne verrez pas beaucoup d'API C implémentées dans ce style, car vous pouvez tout aussi bien appeler votre fonction externe et passer l'instance.

33voto

jxh Points 32720

Comme d'autres l'ont fait remarquer, l'intégration de pointeurs de fonction directement dans votre structure est généralement réservée à des fins spéciales, comme une fonction de rappel.

Ce que vous voulez probablement, c'est quelque chose qui ressemble davantage à un tableau de méthodes virtuelles.

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); }

Or, l'ajout d'opérations supplémentaires ne modifie pas la taille de la base de données. client_t structure. Ce type de flexibilité n'est utile que si vous devez définir de nombreux types de clients, ou si vous voulez permettre aux utilisateurs de votre site Web d'avoir accès à des informations sur les clients. client_t pour être en mesure d'augmenter la façon dont les opérations se comportent.

Ce type de structure apparaît dans le code réel. La couche BIO d'OpenSSL ressemble à cela, et les interfaces des pilotes de périphériques UNIX ont également une couche comme celle-ci.

23voto

rogal Points 279

Que pensez-vous de ça ?

#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;
}

14voto

QSQ Points 426

Cela ne fonctionnera qu'en C++. Les fonctions dans les structs ne sont pas une caractéristique du C.

Il en va de même pour votre appel client.AddClient() ; ... il s'agit d'un appel à une fonction membre, ce qui relève de la programmation orientée objet, c'est-à-dire du C++.

Convertissez votre source en un fichier .cpp et assurez-vous que vous compilez en conséquence.

Si vous devez rester en C, le code ci-dessous est (en quelque sorte) l'équivalent :

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);

}

8voto

Chris Reid Points 89

Vous essayez de regrouper le code selon la structure. Le regroupement en C se fait par fichier. Vous mettez toutes les fonctions et les variables internes dans un header ou un en-tête et un fichier objet ".o" compilés à partir d'un fichier source C.

Il n'est pas nécessaire de réinventer l'orientation objet à partir de zéro pour un programme en C, qui n'est pas un langage orienté objet.

J'ai déjà vu cela auparavant. C'est une chose étrange. Les codeurs, certains d'entre eux, ont une aversion pour passer un objet qu'ils veulent modifier dans une fonction pour le modifier, même si c'est la façon standard de le faire.

Je blâme le C++, car il a caché le fait que l'objet de la classe est toujours le premier paramètre d'une fonction membre, mais il est caché. Ainsi, on a l'impression qu'il ne passe pas l'objet dans la fonction, même si c'est le cas.

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

Le C est flexible et peut accepter de passer des choses par référence.

Une fonction C ne renvoie souvent qu'un octet ou un int d'état et celui-ci est souvent ignoré. Dans votre cas, une forme appropriée pourrait être

 /* add client to struct, return 0 on success */
 err = addClient( container_t  cnt, client_t c);
 if ( err != 0 )
   { 
      fprintf(stderr, "could not add client (%d) \n", err ); 
   }

addClient serait dans Client.h ou Client.c

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X