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. 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.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. IntegerProcessor^ myBlock = ^(int b) {
return a * b;
};
I wasn't aware C supported nested functions.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.
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.
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.
> 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.
Probably, you can't use it.
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.
Do you remember where you picked this up? Any particular book or codebase?
Given that, what's the advantage for "your version" of the idiom?
(This may just be nitpicking.)
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)); 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. 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
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.
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 * .
Pros: beginner confusion; sometimes bugs.
Cons: one less character to type; sometimes able to get more out of a macro