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.
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.
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.
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:
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.
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".
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.