web-dev-qa-db-fra.com

C - fonction dans la structure

J'essaie de créer une fonction dans une structure, jusqu'à présent 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();

}

Erreur: client.h: 24: 2: erreur: attendu: ',', ','; ','} 'ou' attribut 'avant' {'jeton.

Quelle est la bonne façon de le faire?

67
xRed

Cela ne peut pas être fait 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);

}

Cependant, cela ne vous rapporte pas vraiment beaucoup. En tant que tel, vous ne verrez pas beaucoup d’API C implémentées dans ce style, car vous pouvez également appeler votre fonction externe et transmettre l’instance.

91
FatalError

Comme d'autres l'ont noté, l'intégration de pointeurs de fonction directement dans votre structure est généralement réservée à des fins particulières, comme une fonction de rappel.

Ce que vous voulez probablement, c'est plutôt une table 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); }

Maintenant, ajouter plus d'opérations ne change pas la taille de la structure client_t. Désormais, ce type de flexibilité n’est utile que si vous devez définir plusieurs types de clients ou si vous souhaitez permettre aux utilisateurs de votre interface client_t de pouvoir améliorer le comportement des opérations.

Ce type de structure apparaît dans le code réel. La couche OpenSSL BIO ressemble à celle-ci, et les interfaces de pilote de périphérique UNIX ont une couche comme celle-ci.

21
jxh

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

Il en va de même pour votre client.AddClient (); call ... c'est un appel pour une fonction membre, qui est une programmation orientée objet, c'est-à-dire C++.

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

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

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

}
12
QSQ

Que dis-tu 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;
} 
10
rogal

Vous essayez de regrouper le code en fonction de struct. Le regroupement C est par fichier. Vous mettez toutes les fonctions et les variables internes dans un en-tête ou un en-tête et un fichier objet ".o" compilé à partir d'un fichier source c.

Il n'est pas nécessaire de réinventer l'orientation d'objet à partir de zéro pour un programme 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 faire passer un objet qu’ils veulent transformer en une fonction pour le changer, même si c’est la méthode standard pour le faire.

J'en veux à C++, car il cache le fait que l'objet de classe est toujours le premier paramètre d'une fonction membre, mais il est masqué. Il semble donc que l'objet ne soit pas transmis à la fonction, même s'il l'est.

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

C est flexible et peut prendre des choses qui passent par référence.

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

 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

4
Chris Reid