4 votes

Justification du passage d'un pointeur comme paramètre de fonction et de son retour en C

Je suis en train d'examiner le code source (écrit en C) de bkhive -- un utilitaire pour extraire la clé de démarrage SysKey d'un répertoire de stockage de Windows NT/2K/XP -- et j'aimerais savoir s'il y a une justification pour quelque chose que l'auteur original a fait : passer un pointeur à une clé de stockage de Windows NT/2K/XP. struct dans une fonction et de renvoyer le même pointeur. Voici le code source correspondant :

En main() il y a un appel qui ressemble à ceci :

struct hive h;
char *root_key;
// Do some stuff to init
_RegGetRootKey(&h, &root_key)

Quels appels :

int _RegGetRootKey(struct hive *h, char **root_key)
{
    nk_hdr *n;
    n = (nk_hdr*) malloc(sizeof(nk_hdr));

    /* ************************************************
     * RELEVANT FUNCTION CALL
     * Why pass n as a parameter and use return value?
     * ************************************************/
    n = read_nk(n, h, 0x1020);

    if (n->id == NK_ID && n->type == NK_ROOT)
    {
        *root_key = (char *) malloc(n->name_len + 1);
        strncpy(*root_key, n->key_name, n->name_len);
        (*root_key)[n->name_len] = 0;
        free(n);
        return 0;
    }
    free(n);
    return -1;
}

Quels appels :

nk_hdr* read_nk(nk_hdr *nk, struct hive *h, int offset)
{
    memcpy(nk, h->base + offset + 4, sizeof(nk_hdr));
    nk->key_name = (h->base + offset + 4 + 76);
    return nk;
}

Quel est donc l'objectif de l'adoption de la struct et le renvoie ensuite ? La fonction ne pourrait-elle pas ne rien renvoyer et utiliser la fonction n après l'appel de la fonction ?

4voto

Eli Iser Points 2080

Le principal avantage de cette convention est de permettre une concaténation plus simple des appels de fonction. Si vous souhaitez utiliser le retour d'une fonction comme paramètre d'une autre fonction, le fait qu'elle renvoie le pointeur peut vous permettre d'écrire la déclaration en une seule ligne. Ainsi, au lieu d'écrire quelque chose comme ceci :

foo(myPtr);
bar(myPtr);

Vous pouvez le faire :

bar(foo(myPtr));

Le code spécifique que vous montrez n'utilise pas cela, mais c'est une convention utilisée dans de nombreuses fonctions C, et je suppose que l'auteur du code est habitué à cela maintenant.

1voto

Jason Points 20479

Cela vous permet de passer l'objet par référence, puis d'obtenir une poignée (c'est-à-dire un pointeur) vers la valeur mise à jour au retour ... cela vous permet également de renvoyer un NULL si quelque chose ne va pas, afin que vous sachiez que l'état de l'objet que vous avez passé par référence n'est plus bon. Par exemple :

struct my_struct* pass_by_ref = malloc(sizeof(my_struct));
//...some more code

if (foo(pass_by_ref) == NULL)
{
    free(pass_by_ref); //pass_by_ref is no longer any good ...
    perror();
}

1voto

Dmitri Points 4021

Dans ce cas précis, il ne semble pas qu'il soit très utile. Mais en général, il y a deux raisons pour lesquelles j'ai fait la même chose dans le passé :

L'une d'elles est que la fonction peut réallouer l'élément pointé, auquel cas le retour peut être le même pointeur que celui qui a été transmis, ou le remplacer par une valeur différente.

Un autre avantage, même si le pointeur ne change pas, est qu'il permet d'utiliser immédiatement le retour de la fonction pour accéder à l'élément pointé, dans des constructions telles que somefunc(item)->member = 5; entre autres. Il vous permet de placer l'appel de la fonction dans une autre expression qui a besoin du même pointeur par la suite.

Il peut également s'agir de rendre l'utilisation de la fonction cohérente avec d'autres fonctions de l'API, dont certaines peuvent avoir une raison de le faire.

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