Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Personally I don't like when people hide a pointer behind a typedef. If you want to use a typedef, typedef the function and then declare a pointer to that:

    typedef int func(void);

    func *func_ptr;
Avoids the mess of the function pointer syntax, but still makes the fact that it is a pointer clear.


19 years as a C/C++/ObjC developer, and this never occurred to me.

And it works with C Blocks!

    typedef int IntegerProcessor(int);

    int executeTheFunctionPointer(IntegerProcessor* function)
    {
        return function(23);
    }

    int executeTheBlock(IntegerProcessor^ block)
    {
        return block(32);
    }

    int doubler(int a)
    {
        return a * 2;
    }

    int main(int argc, const char * argv[])
    {
        IntegerProcessor* myFunctionPtr = &doubler;

        int a = executeTheFunctionPointer(myFunctionPtr);
        printf("%d\n", a); // 46

        IntegerProcessor^ myBlock = ^(int b) {
            return a * b;
        };

        a = executeTheBlock(myBlock);
        printf("%d\n", a); // 1472

        return 0;
    }
My mind is completely blown.


This is so cool. Where can I find documentation on the following?

   IntegerProcessor^ myBlock = ^(int b) {
      return a * b;
   };

I wasn't aware C supported nested functions.


There's a GNU extension for it.

https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html

But it's not a proper closure, and it's not GC'd, so it's pretty useless.


Last time I checked, Clang doesn't support nested functions although it supports most of GNU extensions (or similar features with slightly altered syntax).

I'm not 100% sure what you mean by "proper closure" but it does capture variables from the outer scope. It has limitations with scopes and lifetimes, of course.


Proper closures require "fat pointers", basically you're storing two pointers, one to the function and one to its context data. (In the case of a nested function that's its stackframe.) They also require that stackframes be generally allocated on the heap.

C doesn't have a type for that, it only has function pointers, which only have space for a single pointer. So what GCC does is actually a horrible hack - it dynamically creates a function (called a trampoline), which calls the actual function with a pointer to its data. But because GCC doesn't have true closures, and only refers to the surrounding function's existing stackframe, which is on the stack, not the heap, this only works until the surrounding function has returned. And since the trampoline is also allocated on the stack, this requires the stack to be executable, which is Not Great for security.


Yes, it's a bit ugly but it still doesn't make it useless. It could be useful for e.g. passing a comparator to qsort using a captured variable to pass the comparison criteria (e.g. compare arrays according to the n'th element).

> So what GCC does is actually a horrible hack - it dynamically creates a function (called a trampoline), which calls the actual function with a pointer to its data.

Well you can call it a horrible hack but it's pretty clever. There's no other way to do this without having a rich runtime system and a language with a built-in concept of a heap (and perhaps a garbage collector).

> And since the trampoline is also allocated on the stack, this requires the stack to be executable, which is Not Great for security.

Yeah - this is pretty nasty. Executable stack is less than useful, although it's not enough to protect against stack/buffer overflow exploits that utilize ROP or other advanced attack methods.

However - in my practical experiments, I have noticed that the optimizer will get rid of most trivial trampolines if the resulting function pointer isn't stored or passed to a function in a foreign translation unit. LLVM in particular is really good in eliminating trampolines.

I wish there was a way to have compile time certainty that no trampolines ever get emitted on the stack. You could still use capturing nested functions with certain limitations.

But yeah - it's not the most useful feature, primarily because it's GCC only and secondarily because, at worst, you'll end up executing a few bytes of machine code from the stack.



So is mine.


Another advantage of typedefing the function is that you can let the compiler help ensure your function definition signatures are correct.

For example, if you typedef a callback type like so:

  typedef int callback_t(int foo);
And then declare a callback like so:

  callback_t my_callback;
And then later define the callback like so:

  int my_callback(int foo) {
    ...
  }
The compiler will produce an error if you screw up the function signature of my_callback() when defining it because it won't match the prototype you defined via the typedef. This only works in C. C++ allows multiple function signatures for the same function name, so you probably won't get a compiler error--though you'll likely wind up with a linker error.

Edit: The downside is that function declarations done this way will look a little odd--possibly mistaken for a variable definition. And, upon further thought, I'm not sure that this pattern really is a huge benefit since function pointer assignment will also produce an error if the signatures don't match. But interesting nonetheless, I guess.


It's never even occurred to me to typedef a function like this, and now that I think about it I'm not sure why. Your way is a lot clearer. Thanks for the tip.

Do you remember where you picked this up? Any particular book or codebase?


I picked it up just reading various C stuff on the internet - I think this one actually came from a Reddit user. It's not a use-case I think I've ever seen used anywhere, except for my personal code. Even then though, I admittedly almost always just type out the regular function-pointer syntax, since I find that function-pointers for me almost always just get declared in one location anyway.


Correct me if I'm wrong, but isn't a "function" always a pointer in C? That is, there's no such thing as a "value function" in C, right?

Given that, what's the advantage for "your version" of the idiom?

(This may just be nitpicking.)


One advantage is that you can declare functions with it, which is useful when you have many different operations of the same type. For example, take a toy calculator:

    typedef double binary_operation(double, double);
    binary_operation add, subtract, multiply, divide;
    double add(double a, double b) { return a + b; }
    /* ... */

    struct binary_operator {
        char const *name;
        binary_operation *operation;
    } binary_operators[] = {
        { "+", add },
        { "-", subtract },
        { "*", multiply },
        { "/", divide },
        { NULL, NULL },
    };
You can also use the function type in parameter lists, but it’s equivalent to a function pointer type.

    int atexit(void function(void));


Well, yeah, obviously there's less redundancy, but I'm specifically not seeing the advantage that OP mentioned. (Which is all that I'm questioning.)


Here's an example:

    typedef void (*sighandler_t)(int);
    sighandler_t signal(int signum, sighandler_t handler);
Without the typedef, it's much less clear.

Edit: It could instead be written as the non-pointer type:

    typedef void (sighandler_t)(int);
And then used as:

    sighandler_t *signal(int signum, sighandler_t *handler);
And as a function declaration:

    sighandler_t foo;
With the pointer in the typedef, the type can't be used to declare functions.


This is very similar to the 'array-type', which I've written about before (And could talk about if you're interested). Functions (and arrays) degrade into a pointer to themselves when used in most situations (for functions, I can't think of a real case where it doesn't degrade, besides declarations). But the 'func' in this case is the type of a 'function' ('value function' as you're referring). Interestingly, declaring something of type 'func' is the same as forward declaring a function of that type:

    typedef int func(void);

    /* These two lines are equivalent */
    func foo;
    int foo(void);
Obviously though, the above is of limited usefulness. It is kinda handy to ensure functions are compatible with a certain typedef, but if it isn't you'll generally see warnings or errors in other locations anyway.

The advantage of my technique here is that it doesn't 'hide' the pointer inside of the typedef, which I consider poor form. Consider these two:

    typedef int type1;
    typedef int type2(void);
    typedef int (*type3)(void);

    type1 *var1;
    type2 *var2;
    type3  var3;
    type3 *var4;
All of the above are actually pointers, but from the declaration alone you can't tell that `type3 var3` actually declares a pointer. In fact, `type3 var3` and `type2 * var2` declare the exact same thing (minus the name), but `type2 * var2` makes it clear that `var2` is a pointer and not a value type. I find this to be a fairly nice aide in reading, and if you keep this consistent for all types then you don't ever have to worry about a pointer being hidden, or the usage not matching the declaration (IE. You declare it as `type3 var3` but then do something like `* var3`, which looks incorrect unless you know `type3` is actually a pointer).

Moreover, lots of people that are newer to C (and even those that aren't but just aren't clear or didn't fully check what `type3` is) will attempt to use `type3 * var`, a double-pointer to a function, when what they really want is `type3 var`, a pointer to a function. There's no confusion over what it is if you don't hide the pointer in the first place, and there's really no great reason to hide it besides not knowing you can avoid hiding it in the first place. Even when you're not new to C, keeping track of things when people do `typedef struct foo * bar` and then `bar * foo2` can get to be a headache really fast.

Edit: Fixed formatting


The main case where a function does not decay into a pointer is in a function call :-)

BUT since ANSI C you can call a function pointer directly: you no longer have to write (*fptr)(arg).

So there is automatic invisible conversion in both directions.


Actually, I used to think this, but I believe it's the other way around. IIRC, the standard says that the `()` operator takes a function pointer before it, and then arguments between the `()`. So when directly calling a function, the name of the function decays into a function pointer which is then used to call the function. Obviously, when you call a function directly a function pointer is not involved internally (The address is just used directly), but the standard still expresses it in that way to make the usage/syntax consistent.

That said, it is possible to see that the function name itself decays into a pointer and isn't a pointer itself. `sizeof(function)` does not return the size of a function pointer, but `sizeof(fptr)` does.

Interesting, function-pointers have the property that they deference to themselves. So `fptr` and `* fptr` are the same thing, as is `* * * * * * fptr` (And also `&fptr`). And since they are the same thing, the `(* fptr) (arg)` syntax works as expected. Personally, I actually prefer to use the `(* fptr) (arg)`, simply because it makes usage of a function pointer clear, but the * really is unnecessary so the benefits are debatable.

The `(* fptr) (arg)` syntax also keeps the "declaration follows usage" pattern intact, since function pointers have to be declared using the * .


I would say that a "function pointer" isn't really a pointer: you can't dereference it or do arithmetic on it. Really, the things we currently call "functions" should be "function literals", and then what's now a "function pointer" could be just a "function".


Functions degrade to pointers when passed as values, but they aren't inherently pointers (and these have distinct types, e.g., for C11 _Generic).


No, but C will automatically take the address. The same goes for arrays. You can explicitly take the address of a function, and this is different from taking the address of a function pointer.

Pros: beginner confusion; sometimes bugs.

Cons: one less character to type; sometimes able to get more out of a macro


Yes. Once declared, function pointers are similar to regular functions. They both point to a value that cannot be changed. That value is a block of code.


+1. This is exactly how I do it, because it's the only sane way I could maintain (even my own) code :)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: