开发者

Rationale for Passing Pointer as Function Parameter and Returning it in C

I'm examining the source code (written in C) of bkhive -- a utility for dumping the SysKey bootkey from a Windows NT/2K/XP system hive -- and would like to know if there is any rationale for something the original author did: passing a pointer to a struct into a function and then returning the same pointer. Here is the relevant source code:

In main() there is a call that looks like this:

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

Which calls:

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

Which calls:

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

So, what is the purpose of passing the struct pointer and then returning it? Couldn't the function return nothing and use n after the function call?


The main benefit of this convention is to allow for simpler concatenation of function calls. If you want to use the return of one function as a parameter to another function, having it return the pointer can enable you to write the statement in a single line. Thus, instead of writing something like this:

foo(myPtr);
bar(myPtr);

You can do this:

bar(foo(myPtr));

The specific code you show doesn't use this, but this is a convention used in many C functions, and I guess the author of the code is used to this by now.


In this exact case, there doesn't appear to be much use for it. But in general, there are two reasons I've done the same thing in the past:

One is where the function might reallocate the item pointed at, in which case the return could be the same pointer that was passed, or could be a replacement for it with a different value.

Another, even when the pointer won't change, is that it allows the return from the function to be used immediately to access the pointed-to item, in constructs like somefunc(item)->member = 5; among others. It lets you drop the function call into another expression that needs the same pointer afterward.

It could also be just to make the function's use consistent with others in the API, some of which may have a reason to do this.


This allows you to pass the object by reference, and then get a handle (i.e., pointer) to the updated value on return ... it also allows you to pass back a NULL if something goes wrong, so that you know the state of the object that you passed in by reference is not good anymore. For instance:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜