4

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?

Gian
  • 327
  • 2
  • 8
  • 1
    If you migrate to C++ you can achieve this with lambda functions or function objects. There are no doubt tricks in C, but that's above my pay grade. – Bathsheba May 04 '19 at 13:57
  • [There's been a soft push to integrate this into C for some time](https://stackoverflow.com/questions/18147676/why-doesnt-c11-support-lambda-functions/18155495#18155495), but the feature doesn't exist yet in a standardized, first-class way. It'll probably be included in C2x (the next standard revision) **if** more compilers than just Clang ever support it. I'm working on that. – Alex Celeste May 04 '19 at 14:02
  • You basically want member functions, if I understand you correctly. That's (one reason) why there is C++. – bitmask May 04 '19 at 14:37

3 Answers3

2

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.

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
1

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

Alex Celeste
  • 12,824
  • 10
  • 46
  • 89
  • @Bathsheba I'm not familar with C++, but I more or less already knew that this kind of things are much easier to achieve with it, since C++ is object-oriented. To tell you the full story, I'm trying to do this in order to try to emulate the object-like structure of other languages in C. I'm not even sure that it would be useful, but I'm really curious to know if it can be done and how. While looking for a solution to this problem, I've stumbled in an article that suggests that C++ achieves object-oriented features by using pointers to functions, which was very interesting to learn. – Gian May 04 '19 at 15:03
  • @Gian there's a classic PDF [Object Oriented C](https://www.cs.rit.edu/~ats/books/ooc.pdf) that might be of interest? What you want *can* be done, but there are a million or two ways! e.g. [1](http://ldeniau.web.cern.ch/ldeniau/html/oopc.html), [2](https://github.com/CObjectSystem/COS), if only because there are a million different styles of OOP to copy. – Alex Celeste May 04 '19 at 15:07
  • this looks like it might be a very interesting read! Thank you for providing this. – Gian May 04 '19 at 18:05
-1

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.

Gian
  • 327
  • 2
  • 8