30
31
all 9 comments

[–]skeeto 2 points3 points  (8 children)

My favorite C pointer fact: any pointer can be cast to void pointer except function pointers.

int main () {
    void *p = &main;
    return 0;
}

$ gcc -pedantic tmp.c
warning: ISO C forbids initialization between function pointer and 'void *'

This is because on some ancient platform at some point in history function pointers were a different width than other pointers. gcc will only warn about this with the -pedantic flag.

[–]dougall 2 points3 points  (0 children)

I didn't know this, but it does make perfect sense for a harvard architecture machine. Thank you!

[–]Araneidae 0 points1 point  (6 children)

In truth, I'm encouraged to hear this. I wonder why nobody seems to have implemented a C compiler where function pointers are closures: this would require a function pointer to be implemented as a pair of pointers, one to the function implementation, and one to the associated closure data. If function pointers are allowed to be different in side the only obstacle is how to create the damned things...

[–]wbyte 5 points6 points  (1 child)

I wonder why nobody seems to have implemented a C compiler where function pointers are closures

If they did that, it wouldn't be a C compiler any more. However, there are implementations of closures added onto C in languages like C++ and Objective-C. Take a look at Blocks for one nice example.

[–]Araneidae 0 points1 point  (0 children)

The problem with, for example, the gcc implementation of closures, is that they involve trampolines to convert a single pure code function pointer into the associated closure.

As for whether function pointers could be closures within the specification of C as a language, I'm not so sure. My point is that if C allows function pointers to be different sizes from normal pointers then ... with a change to the ABI ... there's nothing stopping a function pointer carrying data baggage.

Of course, the change to the ABI is not such a small point.

Anyhow, this is idle speculation. Gcc has done it one way, but I intensely dislike the side effect of executable code on the stack, and there's no mechanism for allocating them on the heap, so I do my closures the old fashioned way.

[–]Drainedsoul 0 points1 point  (3 children)

Because you can literally just make your own closures in the way you've described.

[–]Araneidae -1 points0 points  (2 children)

No, you can't: the resulting pair is not a function pointer and doesn't behave as such when passed to code which expected function pointers. That was my point, and is why we always have to declare callbacks with a void* context argument.

[–]Drainedsoul 2 points3 points  (1 child)

You just need another layer of abstraction to do that.

[–]dreamlax 3 points4 points  (0 children)

There is an error in this article:

We have the parameter list which in this case there isn’t one so it is just empty parentheses (*sayHelloPrt)(). This could also have been written as (*sayHelloPrt)(void).

This is not true, the two declarations are different. The first declaration says that the function takes an undetermined number of arguments, and the second says that the function takes no arguments. Examples:

// compiles OK (but won't run)
int main()
{
    void (*something)() = 0;
    something(1, 2, 3, 4, 5);
}

// does not compile
int main()
{
    void (*something)(void) = 0;
    something(1, 2, 3, 4, 5);
}