Gian
Gian

Reputation: 357

Is it possible to store function arguments in a pointer to function?

Just out of curiosity, I'm trying to understand how pointers to functions work in C.

In order to associate a function to a typedef, I've declared a pointer in it, and then I've stored the address of the desired function in there.

This is what I was able to achieve:

typedef struct
{

    void (*get)(char*, int);
    char string[10];

} password;

int main()
{
    password userPassword;

    userPassword.get = &hiddenStringInput; 

    userPassword.get(userPassword.string, 10);

    return EXIT_SUCCESS;
}

While this does actually work perfectly, I'd like for "userPassword.get" to be a shortcut that when used calls the hiddenStringInput function and fills in the requested arguments (in this case, an array of characters and a integer).

Basically, since I'm always going to use userPassword.get in association with the arguments "userPassword.string" and "10", I'm trying to figure out a way to somehow store those parameters in the pointer that points to the hiddenString function. Is it even possible?

Upvotes: 4

Views: 190

Answers (3)

Gian
Gian

Reputation: 357

So, I've just realized that I can write functions directly inside of structs

typedef struct
{

    char string[10];

    void get(void)
    {
        hiddenStringInput(string, 10);

        return;
    }

    void set(const char* newPassword)
    {
        strcpy(string, newPassword);

        return;
    }

    void show(void)
    {
        printf("%s", string);

        return;
    }



} password;

Now I can just call userPassword.get(), userPassword.show() and userPassword.set("something"), and what happens is exactly what the label says. Are there any reasons I shouldn't do this? This looks like it could come pretty handy.

EDIT: So this is only possible in C++. I didn't realize I'm using a C++ compiler and by attempting to do random stuff I came up with this solution. So this isn't really what I was looking for.

Upvotes: -1

Alex Celeste
Alex Celeste

Reputation: 13370

You can do this in Clang using the "Blocks" language extension. As commented, there have been attempts to standardize this (and it's not been received with hostility or anything), but they're moving slowly.

Translated to use Blocks, your example could look like this:

#include <stdlib.h>

#include <Block.h>

typedef void (^GetPw)(int);             // notice how Block pointer types are used
typedef void (*GetPw_Impl)(char*, int); // the same way as function pointer types

typedef struct
{
    GetPw get;
    char string[10];
} password;

extern void hiddenStringInput(char*, int);

extern void setPw(char dst [static 10], char * src);

GetPw bindPw (GetPw_Impl get_impl, char * pw)
{
  return Block_copy (^ (int key) {
    get_impl (pw, key);
  });
}

int main()
{
    password userPassword;

    setPw(userPassword.string, "secret");

    userPassword.get = bindPw(hiddenStringInput, userPassword.string); 

    userPassword.get(10);

    return EXIT_SUCCESS;
}

There are some subtleties to the way arrays are captured that might confuse this case; the example captures the password by normal pointer and assumes userPassword is responsible for ownership of it, separately from the block.

Since a block captures values, it needs to provide and release dynamic storage for the copies of the captured values that will be created when the block itself is copied out of the scope where it was created; this is done with the Block_copy and Block_release functions.

Block types (syntactically function pointers, but using ^ instead of *) are just pointers - there's no way to access the underlying block entity, just like basic C functions.


This is the Clang API - standardization would change this slightly, and will probably reduce the requirement for dynamic memory allocation to copy a block around (but the Clang API reflects how these are currently most commonly used).

Upvotes: 1

Daniel Jour
Daniel Jour

Reputation: 16156

The way I see this usually done is by providing a "dispatch" function:

void get(password * pw) {
  pw->get(pw->string, 10);
}

Then, after setting userPassword.get to your function, you call just:

get(userPassword);

Obviously this adds some boilerplate code when done for multiple functions. Allows to implement further funny "class like" things, though.

Upvotes: 2

Related Questions